本帖最后由 孤尽 于 2019-8-25 11:20 编辑
JVM中有哪些垃圾回收算法
前言:垃圾回收,在Java虚拟机中,垃圾指的是死亡对象所占用的空间,顾明思议就是对内存中已死的对象进行回收,那么如何找出已死的对象,如何进行回收,已近新的对象内存如何分配,就是垃圾回收要考虑的地方。
1.复制算法 针对新生代的垃圾回收算法
把新生代的内存区域划分成三块,1个Eden区,2个Survivor区,其中Eden区占80%的内存空间,每一个Survivor区各占10%的内存空间,平常可以使用的,就是Enen区和其中一块Survivor区,相当于就是有900M的内存空间是可以使用的。
刚开始对象都是在Eden区的,如果Eden区快满了,就会触发垃圾回收
此时就会把Eden区中的存活对象都一次性转移到一块空着的Survivor区,接着Eden区就会被清空,然后在分配新对象到Eden区,然后就会如上图所示,Eden区和一块Survivor区里是有对象的,其中Survivor区里放的是上一次MinorGC后存活的对象。
如果下次再次Eden区满,那么再次触发Minor GC,就会把Eden区和放着上一次Minor GC后存活对象和Survivor区里的存活对象,转移到另外一块Survivor区去。
对象什么情况下会从新生代转移到老年代
1.默认设置下,如果一个新生代对象躲过了15次GC,他就会转移到老年代里去,可以通过JVM参数“-XX:MaxTenuringThreshold”来设置
2.动态年龄判断,假如新生代内所有对象加起来超过某块新生代区域的一半,此时大于等于这批对象年龄的对象,就会进入老年代
3.大对象直接进入老年代,有一个JVM参数“-XX:PretenureSizeThreshold”,可以把他的值设置为字节数,创建一个大于这个大小的对象,会直接进入老年代
4.如果Minor GC后剩下的对象太多,无法放入Survivor区,此时这些对象会被全部放入老年代
老年代空间分配担保规则
首先,在任何一次Minor GC前,都会去检查老年代可用的内存空间,是否大于新生代所有对象大小
假如大于,可以放心大胆的进行Minor GC
假如小于,首先会看“-XX:-HandlePromotionFailure”参数是否设置,如果有这个参数,会尝试进行下一步判断
下一次判断会判断,老年代的内存大小,是否大于每一次Minor GC后进入老年代对象的平均大小
如果上边判断失败了,或者是参数没设置,此时会进行一次Full GC,对老年代进行垃圾回收,尽量腾出一些空间执行Minor GC
.如果上边判断成功了,就是说可以冒点风险,执行Minor GC 此时会有以下几种可能
第一种可能 MinorGC后,剩余对象大小小于Survivor区大小,此时存活对象会进入Survivor区
第二种可能 Minor GC后 剩余对象大小大于Survivor区 小于老年代剩余内存大小, 此时存活对象会进入老年代
第三种可能 很不幸 Minor GC后 剩余对象大小大于Survivor区 也大于老年代剩余内存大小 老年代也放不下这些对象 就会发生“Handle Promotion Failure”的情况
就会触发一次“Full GC” 如果Full GC后,老年代还是没有足够的大小存放这些对象,那么此时就会导致所谓的OOM内存溢出
2.标记整理算法
老年代触发Full GC的时机:Minor GC之前,检查Minor GC之后要进入老年代的对象太多,老年代放不下,次数需要出发Full GC,要不就是在Minor GC后,发现剩余对象太多放入老年代都放不下,此时会触发Full GC
首先标记出当前老年代存活的对象,然后对存活对象在内存中进行移动,尽量让这些对象都挪动到一边去,让存活对象紧凑的靠在一起,避免垃圾回收之后产生过多的内存碎片
Full GC的速度至少比Minor GC的速度慢10倍以上
|