1.标记清除算法

      当成功区分出内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对象分配内存。

1.1执行过程(先标记后清除)

当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被称为stop the world),然后进行两项工作,第一项则是标记,第二项则是清除。

标记:收集器(Collector )从引用根节点开始遍历,标记所有被引用的对象。
一般是在对象的 Header 中记录为可达对象。标记的是引用的对象,不是垃圾!!

清除:收集器(Collector )对堆内存从头到尾进行线性的遍历,如果发现某个对象在其 Header中 没有标记为可达对象,则将其回收。
注意:这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表里。下次有新对象需要加载时,判断垃圾的位置空间是否够,如果够,就存放覆盖原有的位置。

在这里插入图片描述

1.2缺点

标记清除算法的效率不高。
在进行GC的时候,需要停止整个应用程序,用户体验较差。
这种方式清理出来的空闲内存是不连续的,产生内碎片,需要维护一个空闲列表,就会导致上面的问题出现(明明空间够用,但是却填不进去)

2.标记整理算法

2.1定义

和标记清除一样,标记整理的第一个阶段也是对垃圾对象进行标记,区别主要在第二个步骤,即整理。所谓的整理就是避免之前标记清除时的内存碎片的问题,他就会在清除的过程中,会把可用的对象向前给他移动,这样的话让内存更为紧凑,这就是整理的过程。整理之后,就能发现内存变的更紧凑了,即连续的空间就更多了,这样就不会造成内存碎片。

在这里插入图片描述

2.2优缺点

优点:
整理之后,就能发现内存变的更紧凑了,即连续的空间就更多了,这样就不会造成内存碎片。
解决了“标记-复制算法”需要分配担保的问题。
缺点:
1、“标记-清除算法”在分配对象阶段更为复杂,“标记-整理算法”是移动式回收算法,在老年代中大部分对象都是存活的,因此在回收对象时,会伴随大量的对象移动,从而会导致对象回收阶段会占用相对多的时间
2.如果那些局部变量或对象引用了这个,那么还得改变那些变量或对象的引用地址,因为内存地址变了,所以涉及的工作就比较多一些,牵扯到内存区块的拷贝移动,牵扯到所有引用的地址加以改变。所以速度较慢

3.复制算法

3.1定义

复制算法比较特殊,他把内存区域划分成了大小相等的两块儿区域,左边区域称之为FROM,右边区域称之为TO,其中TO这个区域始终空闲着,即里面一个对象都没有。

3.2执行过程

首先做一次标记(在FROM区域),就找到那些不被根对象引用的对象标记为垃圾,然后在FROM区域这些存活的对象内存空间复制到TO区域中,复制的过程中就会完成碎片的整理,因此也不会产生碎片,等复制完成后,可以看到FROM区域全是垃圾,所以一下子给予清空,并且之后交换FROM和TO他两的位置,即原来的TO变成了FROM,原来的FROM变成了TO,所以TO总是空闲的一块儿。

1.先扫谁是垃圾 2.把好的不是垃圾的放进空的to里面 3.交换to-》form的位置 4.删除垃圾

在这里插入图片描述

3.3优缺点

优点:没有内存碎片
缺点:需要双倍的内存空间(网友戏称双倍快乐)

4.分代垃圾回收

4.1为什么要分代?

一般来说,堆分为新生代和老年代,这样就可以根据各个年代的特点选择合适的垃圾收集算法。

在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成垃圾收集的过程。

而老年代的对象存活率是比较高的,且没有额外的空间对它进行分配,所以我们必须选择 “标记-清除” 或 “标记-整理” 算法进行垃圾收集。

4.2垃圾回收分为哪些类型?

部分收集 (Partial GC):
新生代收集(Minor GC / Young GC):只对新生代进行垃圾收集;
老年代收集(Major GC / Old GC):只对老年代进行垃圾收集。需要注意的是 Major GC 在有的语境中也用于指代整堆收集;
混合收集(Mixed GC):对整个新生代和部分老年代进行垃圾收集。
整堆收集 (Full GC): 收集整个 Java 堆和方法区。

4.3分代垃圾回收的过程

1.对象首先会分配在伊甸园区域
2.新生代空间不足时,触发 minor gc,伊甸园和 from 存活的对象使用 copy 复制到 to 中,存活的对象年龄1并目交换 firom to
3.minor gc 会引发 stop the world,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
4.当对象寿命超过闻值时,会晋升至老年代,最大寿命是15 (4bit)
5.当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STw的时间更长

在这里插入图片描述

4.4相关的VM参数

参数含义
-Xms用于设置JVM初始分配的堆内存大小,即Java虚拟机启动时所占用的内存大小
-Xmx或–XX:MaxHeapSize=size设置最大 Java 堆大小,最大不应该超过总内存的70%
-Xmn或(–XX:NewSize=size+ -XX:MaxNewSize=size)设置新生代大小。整个堆大小=新生代大小 + 年老代大小 + 常量池Sun官方推荐配置为整个堆的3/8
–XX:InitialSurvivorRatio=ratio和–XX:+UseAdaptiveSizePolicy根据应用使用情况,自动调整幸存区的比例。可以根据年轻代(Y)大小和初始幸存区比例®来计算幸存区初始空间(S)大小,公式:S=Y/(R+2)。公式中的 2 代表有2个幸存区,幸存区初始比例®越大,则幸存区初始空间越小。默认值 8。如果年轻代空间是 2MB,幸存区空间则为 0.2 MB。
-XX:SurvivorRatio=ratio设置 eden 区和幸存区 survivor 区比率。默认值 8。
-XX:MaxTenuringThreshold=threshold年轻代晋升老年代的最大年龄阈值。默认值是15
-XX:+PrintTenuringDistribution打印晋升年龄信息。默认禁用此选项。
-XX:+PrintGCDetails -verbose:gc用于打印输出详细的GC收集日志的信息
-XX:+ScavengeBeforeFullGC新生代GC优先于Full GC执行

更多推荐