JVM参考文章:
JVM之 方法区、永久代(PermGen space)、元空间(Metaspace)三者的区别
JRE是java运行时环境而JDK是java开发工具包,JDK包含JRE,但是JRE可以独立安装。
JDK:java development kit (java开发工具),JDK 是用于开发 Java 程序的最小环境。
JRE:java runtime environment (java运行时环境),是提供给 Java 程序运行的最小环境。
JRE包含了java虚拟机、java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。JDK是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。运行java程序只需安装JRE。如果需要编写java程序,需要安装JDK。
在方法区里面有一个运行常量池,包含变量和方法,class文件所有的变量和引用作为符号引用,保存在class文件的常量池中。
描述一个方法调用了其他的方法的时候就是通过常量池中指向方法的符号引用来表示。那么动态连接的作用就是将这些符号引用转化成调用方法的直接引用
所以动态链接:将对方法的符号引用 链接成 对调用方法的直接引用
动态链接(虚方法)发生在运行时,静态链接发生在编译时(private\static\final)
重载是静态绑定,重写是动态绑定
JVM知识梳理之二_JVM的常量池
下面5种情况下会导致类初始化,因此必须在发生这5种情况之前对类进行加载。
可以通过调用 ClassLoader 类的 loadClass ()方法装载类,还可以调用 java . lang . Class .
forName ()方法通过反射的方式完成装载类。 loadClass ()方法只是将 Class 文件装载到 HotSpot VM 中,而 forName ()方法会完成类的装载、链接和初始化过程。
各个类加载器之间并不是继承关系,而是表示工作过程,具体说就是,对于一个加载类的具体请求,首先要委派给自己的父类加载器去加载,只有父类加载器无法完成加载请求时子类加载器才会尝试加载,这就叫"双亲委派"。
类在连接过程中会涉及验证。 HotSpot VM 会遵守 Java 虚拟机的规范,对 Class 文件中包含的信息进行合法性验证,以保证 HotSpot VM 的安全。从整体上看,大致进行如下4方面的验证。
全网最硬核 JVM TLAB(Thread Local Allocate Buffer) 分析
即类型指针,是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
如果对象有属性字段,则这里会有数据信息。如果对象无属性字段,则这里就不会有数据。根据字段类型的不同占不同的字节,例如boolean类型占1个字节,int类型占4个字节等等;
对象可以有对齐数据也可以没有。默认情况下,Java虚拟机堆中对象的起始地址需要对齐至8的倍数。如果一个对象用不到8N个字节则需要对其填充,以此来补齐对象头和实例数据占用内存之后剩余的空间大小。如果对象头和实例数据已经占满了JVM所分配的内存空间,那么就不用再进行对齐填充了。
所有的对象分配的字节总SIZE需要是8的倍数,如果前面的对象头和实例数据占用的总SIZE不满足要求,则通过对齐数据来填满。
为什么要对齐数据?
字段内存对齐的其中一个原因,是让字段只出现在同一CPU的缓存行中。如果字段不是对齐的,那么就有可能出现跨缓存行的字段。也就是说,该字段的读取可能需要替换两个缓存行,而该字段的存储也会同时污染两个缓存行。这两种情况对程序的执行效率而言都是不利的。其实对其填充的最终目的是为了计算机高效寻址。
默认情况下JVM开启了指针压缩,对象A大小情况
new Object() 生成的对象大小为16个字节
手动关闭JVM指针压缩,对象A大小情况
Java对象中实例数据发生的间隙填充alignment/padding gap条件是什么?
图中的连线表示可以使用连线两端的两种收集器分别收集年轻代和老年代的内存空间,而G1收集器既以收集年轻代的内存空间,也可以收集老年代的内存空间。
Serial 收集器是一个单线程的收集器,采用"复制"算法。单线程的意义一方面指它
只会使用一个 CPU 或一条收集线程去完成圾收集工作,另一方面指在进行垃圾收集时必须暂停其他的工作线程,直到收集结束。
Serial 收集器的工作过程如图所示。
Serial 收集器是一个单线程的收集器,采用"复制"算法。"单线程"并不是说只使
用一个 CPU 或一条收集线程去完成垃圾收集工作,而是指在进行垃圾收集时,必须暂停其他的工作线程,直到收集结束。本章将详细介绍 Serial 垃圾回收的具体实现过程。
关于垃圾收集器G1与ZGC
STW的原因?
防止少标或多标(多标产生浮动垃圾)
幸存区复制一次,则年龄增加1。当对象的年龄达到设定的阈值时,将会晋升到老年代。默认情况下,并行 GC 的年龄阈值为15,并发 GC 的年龄阈值为6。由于 age 只有4位,所以最大值为15,这就是﹣ XX : MaxTenuring Threshold 选项最大值为15的原因。
虚拟机给每个对象定义了一个对象年龄计数器。如果对象在 Eden 空间分配并经过第
一次 YGC 后仍然存活,在将对象移动到 To Survivor 空间后对象年龄会设置为1。对象在 Survivor 空间每熬过一次, YGC 年龄就加一岁,当它的年龄增加到一定程度(默认为15岁)时,就会晋升到老年代中。对象晋升老年代的年龄阈值,可以通过﹣ XX : MaxTenuring - Threshold 选项来设置。 ageTable 类中定义 table _ size 数组的大小为16,由于通过﹣ XX : Max - TenuringThreshold 选项可设置的最大年龄为15,所以数组的大小需要设置为16,因为还需要通过 sizes [0]表示一次都未移动的对象,不过实际上不会统计 sizes [0],因为 sizes [0]
的值一直为0。
2.动态对象年龄判定
为了能更好地适应不同程度的内存状况,虚拟机并不总是要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升到老年代。如果在 Survivor 空间中小于等于某个年龄的所有对象空间的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到 MaxTenuringThreshold 中要求的年龄。因此需要通过 sizes 数组统计年轻代中各个年龄对象的总空间。
3.触发 YGC
大多数情况下,对象直接在年轻代中的 Eden 空间进行分配,如果 Eden 区域没有足够的空间,那么就会触发 YGC ( Minor GC ,年轻代垃圾回收), YGC 处理的区域只有年轻代。下面结合年轻代对象的内存分配看一下触发 YGC 的时机:
对于 HandlePromotionFailure ,我们可以这样理解,在发生 YGC之前,虚拟机会先检查老年代的最大的连续内存空间是否大于新生代的所有对象的总空间,如果这个条件成立,则 YGC是安全的。如果不成立,虚拟机会查看 HandlePromotionFailure设置值是否允许判断失败,如果允许,那么会继续检查老年代最大可用的连续内存空间是否大于历次晋级到老年代对象的平均内存空间,如果大于就尝试一次YGC ,如果小于,或者 Handle - PromotionFailure 不愿承担风险就要进行一次 FGC 。