第二章主要讲了jvm的内存区域,也就是jvm对内存的划分

JVM内存结构图

《深入理解Java虚拟机》-周志明 -第3版-第二章摘记_java

线程隔离指每一个线程都有一份(虚拟机栈、本地方法栈、程序计数器)
线程共享,指所有线程都可以直接方法(堆、方法区)

​程序计数器​​:

  字节码的行号指示器、存放执行字节码指令的行号。是分支、循环、跳转、异常处理、线程恢复等功能的底层支持。

​java虚拟机栈​​:

  是线程私有的,它的生命周期 与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都 会同步创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信 息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。(​​可以通过-Xss给每个线程设置栈大小​​)

​本地方法栈​​:

  本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机 栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native) 方法服务。

​java堆​​:

  Java堆是被所 有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java 世界里“几乎”所有的对象实例都在这里分配内存。(​​可以通过参数-Xmx和-Xms设定堆最大内存空间和堆起始空间​​)。

​方法区​​:

  方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的 ​​类型信息​​、常量、静态变量、即时编译器编译后的代码缓存等数据。

​运行时常量池(在方法区内)​

  运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生 成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

​直接内存​

  直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中 定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。


自己的总结:

  类的static属性、字面量常量会编译成字节码指令集,在类加载的过程中,成员属性、字面量常量、类的定义信息会存入方法区、当我们启动主线程执行mian方法内时就是将这个main方法所包含的字节码指令集以栈帧的方式压入进虚拟机栈,然后执行栈帧内指令,而我们平常​​new​​创建对象就相当于将方法区内该类的构造方法指令集以栈帧的方式压入到同一个栈的顶部,执行完​​new​​指令后(​​在堆的Eden区分配一块空间,实例化后就相当于根据方法区的模板得到了一个对象。​​)继续执行new指令后面的操作,就可以通过堆对象调用对象的属性。

  代码中有一些字面量的字符串常量在类加载过程中会加载进字符串常量池,而 ​​字符串常量池存在于堆的Old区域(jdk1.8)​​,而方法区则在元空间​​MetaSpace​​中,也就是说类信息是存入​​MetaSpace​​中的,而​​MetaSpace​​的位置在堆外内存,也就是直接内存只受宿主机的真实内存影响。


​对象在内存中的分布​

  在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例 数据(Instance Data)和对齐填充(Padding),对象的大小一定是8 byte的整数倍,如果不是则会通过填充进行对齐。

截取书中部分截图

《深入理解Java虚拟机》-周志明 -第3版-第二章摘记_java_02

HotSpot虚拟机默认的内存分配顺序为longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers,OOPs),从以上默认的分配策略中可以看到,相同宽度的字段总是被分配到一起存 放,在满足这个前提条件的情况下,在父类中定义的变量会出现在子类之前。如果HotSpot虚拟机的 +XX:CompactFields参数值为true(默认就为true),那子类之中较窄的变量也允许插入父类变量的空 隙之中,以节省出一点点空间。

​对象的访问定位​

  主流的访问方式主要有使用句柄和直接指针两种:

《深入理解Java虚拟机》-周志明 -第3版-第二章摘记_java_03

《深入理解Java虚拟机》-周志明 -第3版-第二章摘记_方法区_04

​实战:OutOfMemoryError异常​

​Java堆溢出​​:堆的 最小值-Xms参数 与 最大值-Xmx参数

​虚拟机栈和本地方法栈溢出​​:栈容量只能由-Xss参数来设

​方法区和运行时常量池溢出​

jdk1.7及以前:-XX:PermSize和-XX:MaxPermSize限制永久代的大小

jdk1.8开始以:-XX:MetaspaceSize初始元空间大小 和 -XX:MaxMetaspaceSize最大元空间大小

-XX:MinMetaspaceFreeRatio:作用是在垃圾收集之后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率。类似的还有-XX:Max-MetaspaceFreeRatio,用于控制最大的元空间剩余容量的百分比。

​本机直接内存溢出​​:通过-XX:MaxDirectMemorySize参数来指定,如果不去指定,则默认与Java堆最大值(由-Xmx指定)一致。