JVM运行时数据区域

作者: 北国雪WRG | 来源:发表于2019-01-23 15:28 被阅读0次

java 和 C++之间有一堵有内存动态分配和垃圾回收技术所围城的高墙,墙外面的人想进去,墙里面的人想出来。

首先要明确一个问题!为什么要了解JVM? 我们把内存分配的工作交给JVM,如果我们 和它配合的不默契,那么出现问题(内存泄露,内存溢出)将是一件很脑壳痛的事情。要解决OutOfMemoryErrorStackOverflowError我们就需要翻越这堵墙,看清楚墙里面的世界。

翻墙第一步,了解运行时数据区域


运行时数据区

首先可以把这个区域按照是否线程共享分为两个部分:蓝色和绿色部分。

程序计数器PC

这和计算机CPU中的程序计数器大致一样,这一块实际上很小的,图画的有点问题。其保存的就是当前代码执行的位置。线程是可以并发的,所以每个线程有自己的PC。需要注意的是

  1. 当执行的是JAVA方法,PC指向的是虚拟机字节码指令的地址
  2. 执行的是Native方法,这个计数器值为空。
  3. 这个区域是不会发生 OutOfMemoryError的。我的理解是它只是存储一个地址而已。

JAVA虚拟机栈

这个栈用来存储方法被调用的时候产生的局部变量表(基础数据类型和对象引用),操作数栈,动态连接等。这些数据除了long和double类型8Byte占用2个Slot(局部变量空间)外其他数据都是占用一个Slot。
每调用一个方法都会创建一个栈帧,并压栈。执行完成后弹栈。

  1. 当栈深大于最大深度的时候,抛出StackOverflowError
  2. 虚拟机大多数可以动态扩展,如果扩展无法申请足够的内存会OutOfMemoryError

本地方法栈

本地方法栈和JAVA虚拟机栈一样。
本地方法栈存储的是Native方法调用关系,变量等,具体的实现虚拟机规范没有规定。也会抛出StackOverflowErrorOutOfMemoryError的错误。

JAVA堆 - 线程共享

这是JVM管理内存最大的一块了,它是用来存放所有的对象实例。(注,JIT编译,逃逸分析等技术让所有不再绝对)
这也是垃圾回收主要工作的区域,所有JAVA堆又叫GC堆。GC堆可以进一步划分
按照垃圾回收的角度:新生代和老年代
按照内存分配的角度:多个线程私有分配缓冲区TLAB
划分的目的在于方便内存管理。

方法区 - 线程共享

存储:类信息,常量,静态变量等。有的时候这个区域被成为永久带,原因是GC在这里很少出现,但是这是不准确的,并非这里的数据就永久存在。

运行时常量池 - 方法区的一部分

存储:类的版本,字段,方法,接口,常量
具备动态性:运行时候可能有新的常量放入池中(暂时不是很理解)
因为运行时常量池是方法区的一部分,所以内存自然受到方法区的限制,当无法申请到新的内存的时候,会抛出OutOfMemoryError

直接内存

这个内存并不是JAVA虚拟机规范中定义的区域。我暂且理解为是物理机内存中不属于JVM的一个内存块。
JDK1.4中,NIO类的IO操作时候,读取或写入的数据Buffer就是在直接内存区域,这样可以提高效率,然后通过堆中的DirectByteBuffer对象作为这个区域的引用。主机物理内存有限,可能出现OutOfMemoryError

相关文章

网友评论

    本文标题:JVM运行时数据区域

    本文链接:https://www.haomeiwen.com/subject/obwjjqtx.html