JVM学习日记- 。-JVM体系结构

379 阅读5分钟

“这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

引言 今天是搞JVM的第三天,前两天没什么干货,今天带大家肝一肝硬核的东西,有多硬?先按下不表,今天来说说JVM虚拟机的内存区域。

为什么学?(why

作为一个每天都和JAVA打交道的开发程序员,我想大家都会遇到过栈溢出或者内存溢出的问题,那遇到问题我们是首先查百度,百度到了还好,百度不到呢?问公司所在的高T,高T有空还好,要是没空呢?所以啊。我们要学清华大学的同学,学他们的自强不息(又开始洗脑了),那怎么做呢?我们得首先了解这个虚拟机是怎么使用内存的,内存是如何划分的,以及每个部分的作用是什么,会产生哪些问题等等(醒醒吧,不要只知道堆和栈了)。

运行时的数据区域

JVM会在程序运行的时候将它所管理的内存划分为几个区域,这些区域名称不同,分工也不同,包括:

  • Method area
  • VM stack
  • Native Method Stack
  • heap
  • Program Counter register

PC register

程序计数器,最早是来源于程序寄存器,在JAVA中字节码解释器可以通过改变它的值来执行需要执行的字节码指令,不光如此,我们的程序控制、分支、循环、跳转、异常处理、线程恢复都需要依靠它来完成,哈哈哈是不是很强大,你可千万别以为它就是个计数的。

由于一个处理器在同一时刻只能执行一条线程的指令,那执行完这一条之后,如何保证处理器在切换回来的时候是原来的执行位置呢,那必然要有一个东西来记住这个位置,没错,这个活就由程序计数器来肝,java支持多线程,所以呢就给每个线程派一个小弟,你就帮我计数,之后告诉处理器执行到哪了,专业术语叫线程私有,哈哈咱没那么专业。

《java虚拟机规范》中交代了:如果线程正在执行的是一个java method,那程序计数器就正在执行的方法指令的地址,如果是native method,计数器的值就是undefiend

VM stack

与程序计数器一样,是线程私有的,与线程生命周期相同。在java中是用来描述方法执行的线程模型的,就是和方法执行有关的模型,每个方法执行的时候,线程会为每个方法创建一个栈帧(Stack Frame),包含:局部变量表,操作数栈,动态链接,方法出口等信息。简单讲:方法的执行与结束就是一个入栈出栈的过程,你走进超市,开始消费,出来,消费结束。

//todo 局部变量表,栈帧 先按下不表

《java虚拟机规范》中交代了:如果线程请求的栈深度>虚拟机给的,抛Stack Over flow error。PS:只要线程申请栈成功就不会有OOM,否则会。

Native Method Stack

顾名思义,只要是本地方法就在这玩。

《java虚拟机规范》中交代了:对本地方法的使用语言,使用方式,数据结构没有明确的限制,可以按需实现。但本地方法栈在栈深度溢出或者扩展失败时也会分别抛出Stack Over flow error和out of memory error

Heap

堆是被所有线程共享的一块区域,在虚拟机启动时创建。在java中是用来存放对象的一块区域,故也是占地最大的一块区域。《java虚拟机规范》中交代了:所有的对象和数组都应在堆上分配,但由于java多年的发展尤其是即时编译技术的进步,更多优化手段导致在java堆上分配也不是那么绝对(PS:即时编译、逃逸分析、标量替换、栈上分配先按下不表)。

java heap也是垃圾收集管理的内存区域,就是GC,这个大家绝对背过(young old eden from to 先按下不表),但是我要说的是垃圾回收也只是部分基于分代收集思想的,并不是全部基于,也有不使用分代收集的新垃圾回收器。

这里还可以提到TLAB,是线程私有的分配缓冲区,可以提升对象分配时的效率(先按下不表,有兴趣的可以看张哈希写的TLAB,非常的硬核,本人很喜欢,就在我的关注里)。无论java堆如何细分,有一点是不变的就是为了更快的对象分配,更快的处理垃圾(处理细节先按下不表)。

《java虚拟机规范》中交代了:java堆是内存不连续的区域,java堆是可扩展的(-xmx -xms),当java堆没有内存完成实例分配并且堆也不能扩展时就会抛out of memory error

Method erea

java堆一样,是线程共享的区域,用来存储被VM加载的类型信息,常量、动态变量、编译后的代码数据等,还有个别名叫非堆(non-heap)。

《java虚拟机规范》中交代了:如果方法区没有满足新的内存分配时就会抛out of memory error

Runtime Constant Pool

常量池用于存放各种字面量和符号引用,我们常见的就是String

《java虚拟机规范》中交代了:如果常量池没有满足新的内存分配时就会抛out of memory error

题外话: 今日疲惫且充实!