Garbage Collect(垃圾回收)
如何确定一个对象是垃圾
1. 引用计数
判断当前应用程序中,只要还持有当前对象的引用,就代表该对象不是垃圾.如果没有任何指针指向其引用,它就是垃圾
缺陷: 当两个对象循环依赖 ,互相持有对象的引用,那么采用此方法就无法判断出当前两个对象是垃圾
2. 可达性分析
从一个GC Root 出发 ,如果能够到达一个对象 ,那么久证明此对象不是垃圾
可作为GC Root的有 : 方法区的静态变量,常量,虚拟机栈的局部变量表(栈帧内存储)等
垃圾回收算法
1. 标记--清除
缺点: 会产生大量的空间不连续碎片
2. 复制
3. 标记整理
a : 对于堆的young区而言, 算法采纳 复制. 因为一个web项目大部分对象都是朝生夕死,线程结束,就像就变为垃圾.所以其实存活下来复制到S0或者S1的对象并不多,所以采用此算法
b : 对于堆的old区而言,标记清除或标记整理(Old区对象存活时间比较长,复制来复制去没必要,不如做个标记再清理)
线程结束,对象就变为垃圾 : 因为栈是随着线程的结束而结束, 如 Person person = new Person(),存储于局部变量表中的 person 随着线程消失就不存在了,那么存放于堆中的Person实例就不存在有人会指向它的引用,符合成为垃圾的标准,即下一次GC就可以清除掉了. 感觉与cookie和session比较相似,当浏览器关闭,cookie消失,其实session并未消亡,除非session过期时间到了或者调用方法让其直接消亡.否则它还是存在的,只是没有cookie能指向它了.
垃圾收集器类型
G1 : 既适用于young 也适用于old区.
特点:
a : 可预测的停顿 : 在于此收集器可以设置停顿时间,但是不要太严格. (也就是用户可以设置程序的GC时间,即使垃圾未全部GC结束,也要停止)
b: 采用G1收集器时,Java堆的内存布局与其他收集器不同,逻辑上 old区, young区, S0 和S1 还是存在的,但物理上已经被分成一个个大小相等的独立区域(Regison) ,新生代和老年代已经不是物理隔离的了.并且可以不连续
理解JVM调试中常说的吞吐量和停顿时间
吞吐量 : 运行用户代码时间 / 运行用户代码时间 + GC时间 (运行用户代码时间越大,其实这个值也就越大)
a : 吞吐量越大,高效利用cpu,只要运用于后台的运算,而不需要过多的与用户交互
停顿时间 : 垃圾收集器进行拉垃圾回收,终端应用执行响应时间.
a : 停顿时间越短,越适用于web端与用户的交互,较快的响应速度带来极好的用户体验.
如何选择一个垃圾收集器
官网说明: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref28