GC
作用区域:
![image-20210815101348942](https://pic-bed-1303913583.cos.ap-nanjing.myqcloud.com/img/image-20210815101348942.png)
JVM在进行GC时,并不是对这三个区域统一回收。大部分时候,回收都是新生代
-
新生代
-
幸存区(form,to)
-
老年区
GC两种类:轻GC(普通的GC)(新生代,幸存区),重GC(全局GC)(全部)
GC题目:
1、JVM的内存模型和分区,详细到每个区放什么?
由栈、堆、本地方法栈、方法区、程序计数器
-
栈:方法、对象的引用、8大基本数据类型
-
堆:实例的对象,成员变量(非static)
-
方法区:方法区是所有线程共享的,所有定义的方法的信息都保存在该区域,静态static修饰的变量和方法,final修饰的,类信息,常量池
-
程序计数器:存储指向下一条指令的地址
-
本地方法栈:它登记native方法,在(Execution Engine)执行引擎的时候加载Native Libraies(本地库)
2、堆里面的分区有哪些?说说他们的特点
Eden,from,to,老年代,
-
Eden:所有的对象都是在这new 出来的,它是对象出生,生长,也可能是死亡的地方。每次GC后,Eden重新变成空的,因为我们创建的大部分都是临时对象,所以对象的淘汰率还是很高的,适合GC的复制算法(将from的对象复制到to里,之后二者交换身份)。
-
from和to: 经过GC清除后,幸存的对象会移动到to里面,它和from是动态交换的,to里面永远是空的
-
老年代:在幸存区经过一定的清除次数后的对象会被移到老年代,这个区域的对象就很难被杀死了,再使用复制算法就成本太高,适合GC的标记清除算法和标记压缩算法的结合
3、GC的算法有哪些?
- 复制算法
- 标记清除
- 标记压缩
4、轻GC和重GC分别在什么时候发生?
在Eden对象满了之后就会触发轻GC,当老年代里面存储的对象也满了之后会触发重GC
-
引用计数法
每一个对象分一个计数器,空间消耗
因为它并不高效,所以jvm并不使用它
复制算法
谁是to的问题,:谁空谁是to
1、每次GC都会将伊甸园区活得对象移到幸存区中,一旦Eden区被GC后,就会是空的!
2、复制算法为了保证to区是干净的,将form里面的对象移到to,复制过去后二者身份立马交换,动态的
3、当一个对象经历了15次(默认)GC还没有死,就会进入老年代。,默认次数可以修改
-XX: -XX:MaxTenuringThreshold=20 ( jvm堆内存调优)通过这个参数可以设定进入老年代的时间
演示GC时幸存的对象的移动
第一次GC时,从Eden活下来的要往to里面去,同时from里面的也复制到to里面去
本次GC后的结果:Eden变成空的,from和to身份互换
即每一次垃圾回收之后Eden和to区都是空的
假设from满了达到了次数,就会去老年代
复制算法的好坏处:
- 好处:没有内存的碎片
- 坏处:浪费了内存空间(多了一半空间永远是空 to)。假设对象100%存活(极端情况),这样的话复制算法要求成本就比较高
复制算法最佳使用场景:对象存活度较低的时候(新生区),所以新生区里面使用复制算法
标记清除算法
对存活的对象做一个标记,没有标记的对象进行清除
标记占内存,清除完有空档,两次扫描的时间消耗
- 优点:不需要额外的空间(干掉了复制算法的缺点)
- 缺点:两次扫描,严重浪费时间,会产生内存碎片。
标记压缩
优化内存碎片的问题。
压缩:防止内存碎片的产生。 再一次扫描,向一端移动存活的对象,但是有了一个时间成本。
又称为标记清除压缩算法
标记清除压缩
先清理几次标记清理,这样的话会产生很多碎片,
![image-20210815110952984](https://pic-bed-1303913583.cos.ap-nanjing.myqcloud.com/img/image-20210815110952984.png)
然后再使用压缩
![image-20210815111040136](https://pic-bed-1303913583.cos.ap-nanjing.myqcloud.com/img/image-20210815111040136.png)
这样连起来会少一点时间成本
总结
内存效率:复制算法 > 标记清除算法 > 标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法 > 标记清除算法
内存利用率:标记压缩算法 = 标记清除算法 > 复制算法
思考一个问题:难道没有最优算法嘛?
答案:没有,没有最好的算法,只有最适合的算法。 所以GC:分代收集算法
即年轻代因为对象存活率底,所以适合使用复制算法。
而老年代因为区域大,存活率高,适合使用标记清除+ 标记压缩混合 实现,
则涉及到调优,保证内存碎片不是太多的情况下,到达一个量级后再压缩一次
答案:没有,没有最好的算法,只有最适合的算法。 所以GC:分代收集算法
即年轻代因为对象存活率底,所以适合使用复制算法。
而老年代因为区域大,存活率高,适合使用标记清除+ 标记压缩混合 实现,
则涉及到调优,保证内存碎片不是太多的情况下,到达一个量级后再压缩一次