G1 收集器
一个面向服务端应用的垃圾收集器。特点
- 并行与并发
可以使用多个CPU来缩短Stop-The-World停顿时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器可以通过并发的方式让Java程序继续执行。
Stop-The-World 是指让收集器进行Full GC 的时候因为要暂停所有的Java程序,再进行GC动作。 - 分代收集
新生代和老年代 - 空间整合
G1运行期间,不会产生内存空间碎片。分配大对象的时候不会因为无法找到连续内存空间而提前触发再一次GC。 - 可预测的停顿
可以让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫米。
内存分配
- 对象优先在Eden分配
大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配的时候,虚拟机会进行一次Minor GC。 - 大对象直接进入老年代
需要大量连续内存空间的Java对象,直接进入老年代。 - 长期存活的对象进入老年代
虚拟机给每个对象定义了一个对象年龄计数器,如果对象在Eden出生并且经历第一次Minor GC 仍然存活,并且能够被S区容纳,将会被移动到s区,对象年龄此时为1。当在S区的对象每经历一次Minor GC 且没有被回收,那么它的对象年龄+1,当达到一定次数(一般为15次)就会从s区进入到老年代。 - 动态对象年龄判定
如果S区某个对象的大小超过了当前S区空间的一半会直接进入老年代。 - 空间分配担保
在进行MInor GC之前,虚拟机会先检查老年代最大可用连续空间是否大于新生代所有对象的总空间。
如果允许就直接进行一次Minor GC。
如果不允许查看是否允许担保失败。
允许担保的话,会检查每次晋升到老年代的平均空间大小,如果此时连续空间大于的话就会进行一次MInor GC。如果进行失败那么老年代进行一次Full GC 。
如果不允许就进行一次Full GC。
虚拟机类加载机制
类的生命周期:
验证,准备,解析都属于连接阶段。
-
加载
- 通过一个 类的全限定名来获取此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的Java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。
-
验证
验证是连接阶段的第一步,主要是为了确保Class文件的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。- 文件格式验证
验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。 - 元数据验证
对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求。 - 字节码验证
通过数据流和控制流分析,确保程序语义是合法的,符合逻辑的。
对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出虚拟机安全的事情。 - 符号引用验证
对于常量池中各种符号引用的信息进行匹配性校验。
- 文件格式验证
-
准备
为被Static修饰的变量分配内存并设置该变量初始值。注意的是例如static int value = 123,这时候初始值为0,不是123除非value 前面修饰为static final 才会是123
-
解析
虚拟机将常量池内的符号引用替换为直接饮用的过程 -
初始化
执行类构造器()方法的过程。
()方法是由编译器自动收集类中所有的类变量赋值动作和静态语句块中语句合并产生的。- 编译器收集的顺序是由语句在源文件中出现的顺序决定,静态语句快可以访问定义到静态语句快之前和之后的变量,但是如果变量定义在静态语句块之后,那么该静态语句块只能对变量进行赋值,但是不能访问。
- 虚拟机中第一个被执行的()方法的类是java.lang.Object
- 父类的()方法优于子类的。也就是说父类的静态语句块优先于子类的静态赋值。
- 接口中不能使用静态语句块。但是仍然会有变量初始化的赋值操作,接口的()方法执行的时候不会先执行父类的,只有当父类接口中定义的变量被使用的时候才会初始化。
- 多线程加载时,只会有一个去加载,轮到其他线程的时候,不会再去加载()方法。
-
使用
-
卸载