JVM学习笔记一:JVM运行时数据区

最近重读周志明老师的《深入理解Java虚拟机》,结合网络参考资源和视频,对JVM加深了印象且又有一番新的理解,现总结如下(文章图片和内容参考《深入理解Java虚拟机》一书和网络资源,如有侵权请联系我处理).

一、JVM运行时数据区

JVM学习笔记一:JVM运行时数据区_第1张图片

程序计数器是一块较小的内存空间,可以看作当前线程所执行字节码的行号指示器。由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,任何时刻,一个处理器都只会执行一条线程的指令,为了线程切换后能恢复到正确的执行位置,每个线程都需要一个独立的程序计数器,各线程之间互不影响,独立存储,所以PC计数器是线程私有的内存。此内存区域是JVM规范中唯一一个没有规定任何OutOfMemoryError情况的区域。

虚拟机栈描述的是Java方法执行的内存模型:每个方法再执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直到执行完成的过程,就对应着一个栈帧在JVM中入栈到出栈的过程。它是线程私有的,生命周期与线程相同。JVM规范中,对栈区规定了两种异常状况:如果线程请求的栈深度大于jvm所允许的深度,将抛出StackOverflowError异常;如果栈区可有动态扩展,扩展时无法申请到足够的内存,则抛出OutOfMemoryError异常。

本地方法栈与虚拟机栈的作用非常类似,区别是虚拟机栈为java方法(也就是字节码)服务,而本地方法栈则为用到的Native方法服务。本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。

Java堆是所有线程共享的JVM管理中最大的一块内存,几乎所有的对象实例都在这里分配内存(虽然JVM规范描述的是所有的对象实例以及数组都要在堆上分配,但是由于JIT编译器逃逸分析技术的发展和成熟,栈上分配、标量替换优化技术,并不是所有对象都分配在堆上)。Java堆细分为新生代和老年代,新生代细分为Eden区、From Survivor区、To Surviror区。还可能花费出多个线程私有的分配缓冲区(Thead Local Allocation Buffer,TLAB)。Java堆是GC的主要区域。如果堆中没有内存完成实例分配,并且堆也无法扩展时,会抛出OutOfMemoryError异常。

方法区也是线程共享的内存区域,用于存储已被JVM加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据。JVM规范中把方法区描述为堆的一个逻辑部分。在HostSpot中,由于Hotspot设计团队把GC分代收集扩展至方法区,很多人把方法区称为“永久代”;但对于其他虚拟机来说是不存在永久代的概念的。Hotspot的JDK1.8中将永久代改为metaspace(参考:https://www.cnblogs.com/dennyzhangdd/p/6770188.html)

二、JVM创建对象的过程:

检查:JVM在遇到一条new指令时,首先去检查这个指令的参数是否能在常量池中定位到一个类的引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,必须先执行相应的类加载过程。

分配内存:在类加载检查通过后,分配内存(对象所需内存大小在类加载完成后可确定)。分配算法有两种:指针碰撞(Bump the Pointer)和空闲列表(Free list);如果Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存放在另一边,分配内存就是将位于中间的指针向空闲内存移动所需内存大小的距离即可,这种方式称为指针碰撞;若Java堆中内存不规整,JVM维护一个列表记录可用内存块,分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种方式称为空闲列表。GC收集器的压缩整理功能会决定JAVA堆是否规整,从而决定采用哪种分配方式。Serial、ParNew等带有compact的过程的收集器采用指针碰撞法,CMS(基于标记-清除算法)等采用空闲列表。

内存分配过程中如何解决并发问题:两种方案:

一、采用CAS加失败重试的方式保证更新操作的原子性。

二、使用本地线程分配缓冲(TLAB),只有TLAB用完并分配新的TLAB时,才需要同步锁定。(通过-XX:+/-UseTLAB设定)

初始化内存空间:JVM将分配到到的内存空间都初始化为零值(不包括对象头)。

设置对象:设置对象头内容,如这个对象是哪个类的实例,对象的哈希码,对象的GC分代年龄等。

三、对象的内存布局

对象头(Header):对象头包含两部分信息,第一部分存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID、偏向时间戳等,第二部分时类型指针,通过这个指针确定这个对象是哪个类的实体。

实例数据(Instance Data)

对齐填充 (Padding)

四、对象的访问定位

句柄访问

直接指针

你可能感兴趣的:(java)