《深入理解Java虚拟机》-垃圾收集器与内存分配策略

Jvm垃圾回收分为俩点,一是对象的内存回收也就是堆内存回收,二是字面量(运行时常量池)和类信息内存回收也就是方法区内存回收。

1,对象内存回收判断

1)引用计数算法
即给每个对象设置一个引用计数器,每当有一个地方引用它时,引用计数器加一,当为0时,选择内存回收。引用计数法实现简单,判定效率也高,但它无法解决对象之间循环引用的问题。主流的java虚拟机不采用这种方法来管理内存
2)可达性分析算法
通过一系列的称为“GC Roots”的对象作为起始点,从GC Roots到这个对象不可达,即该对象不可用。
在Java语言中,GC Roots分为以下几种
* 虚拟机栈(栈帧中的本地变量表)中引用的对象
* 方法区中的类静态属性引用的对象
* 方法区中的常量引用的对象
* 本地方法栈中JNI(native方法)引用的对象
GC管理的主要区域是Java堆,一般情况下只针对堆进行垃圾回收。方法区、栈和本地方法区不被GC所管理,因而选择这些区域内的对象作为GC roots

2,回收方法区

Java虚拟机规范中确实说过不要求堆方法区实现垃圾收集。就算对垃圾回收,一般性价比比较低,但是方法区还是可以垃圾回收的。
方法区的垃圾收集主要包括两部分:无用常量和无用的类
1)常量:在常量池中的常量没有被引用后,若进行垃圾回收,在需要的情况下,该常量会被回收
2)类:判断一个类是否满足被回收的条件
* 该类的所有实例都被回收,即Java堆中不存在该类的实例
* 加载该类的ClassLoader已经被回收
* 该类对应的Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

3,四大引用

自jdk1.2之后,Java将引用分为四种,分别是 强引用、软引用、弱引用、虚引用。
1)强引用:永远不会被回收
2)软引用:将要发生内存溢出之前,将会把软引用的对象进行回收SoftReference类实现软引用。
3)弱引用:对象只能生存在下一次gc之前。WeakReference类来实现弱引用
4)虚引用:虚引用无法用来取得一个对象的实例。虚引用不会对对象的生存时间有任何影响,只是能在这个对象被回收时收到一个系统通知。

4,finalize方法

一个对象要真正的被回收需要经过两次标记过程。第一次标记是指在可达性算法中,判断对象不可达。会将对象进行第一次标记。然后判断该对象是否有必要执行finalize方法。finalize方法是否有必要判断条件:该对象是否覆盖finalize方法,Jvm是否调用过了finalize方法。如果在finalize方法中,该对象成功被引用,即这个对象会被移除“即将回收”的集合。
注意:一个对象的finalize方法最多只会被系统自动调用一次。finalize方法运行代价高昂,不确定性大,无法保证各个对象的调用顺序,建议尽量不使用该方法

5,垃圾收集算法

1)标记-清除算法
标记所有需要回收的对象,然后统一回收。缺点:效率不高,产生大量不连续的内存碎片导致内存泄漏。
2)复制算法
将内存划分为相等大小的两块s1,s2。每次只使用s1,在进行内存回收时,将存活的对象复制到s2中,然后把s1一起回收。缺点:内存减半
3)标记-整理算法
标记素有需要回收的对象,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
4)分代收集算法
将内存区域分为新生代和老年代。新生代每次垃圾回收时,只有少数对象存活,推荐复制算法。当新生代内存不够时,老年代给新生代作分配担保。老年代每次垃圾回收时,大量对象存活,推荐使用标记-整理算法。

6,HotSpot算法实现

1)枚举GC Roots
HotSpot使用的是准确式GC,所以当执行线程停下来之后,并不需要检查全文的所有位置。在类加载完成后,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译时也会在特定位置记录栈和寄存器哪些位置是引用。这些都存储在OopMap这个数据结构中。
2)安全点
不懂
3)安全区域
不懂

7,垃圾收集器

《深入理解Java虚拟机》-垃圾收集器与内存分配策略
垃圾回收器分为七种:分别是serial、parnew、parallel scavenge和cms、serial old、 parallel old、G1;其中serial、parnew、parallel scavenge用于年轻代,cms、serial old、 parallel old用于年老代,g1用于年轻代和年老代。所有收集器都存在stop the world,不过在java发展中 一直在优化停顿时间。
年轻代:
1)serial:是一个单线程的收集器,在垃圾回收时,必须暂停其他所有的工作线程。直至它收集结束。是最基本,发展历史最悠久的搜集器
2)parnew:适用于年轻代,serial收集的多线程版本,可以和CMS收集器配合使用
3)parallel scavenge:适用于年轻代垃圾回收,复制算法,jdk1.4发布,属于多线程,无对stop the world优化,它是一个可以控制吞吐量的收集器,拥有自适应调节策略;需要注意一点的是,gc停顿时间缩短是牺牲吞吐量和新生代空间来换取的。
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
自适应调节策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整参数以提高最合适的停顿时间或最大吞吐量。
老年代:
4)serial old:单线程,使用标记-整理算法。主要用于client下的虚拟机,如果用在server模式下主要有俩个作用:一是jdk1.5以及之前用于与Parallel Scavenger搭配使用,二就是为cms提供后备预案。
5)parallel old:适用于年老代垃圾回收,标记-整理算法,jdk1.6发布,属于多线程,注重于吞吐量控制,是为了Parallel Scavenge定制的;