基础垃圾回收算法
标记-清除(Mark-Sweep)
- 标记需要回收的对象(前文的使用可达性分析来判断标记)
- 清理掉需要回收的对象
标记-整理(Mark-Compact)
- 标记需要回收的对象
- 把所有的存活对象压缩到内存的一端
- 清理掉边界外所有的空间
复制(Copy)
- 把内存分为两块,每次只使用一块
- 将正在使用的内存中的存活对象复制到未使用的内存中去,然后清除掉正在使用的内存中的所有对象
- 交换两个内存的角色,等待下次回收
三种算法对比
综合垃圾回收算法
分代收集算法
把内存分成多个区域,不同区域使用不同的回收算法回收对象
增量算法
每次只收集一小片区域的内存空间的垃圾,减少系统的停顿
分代收集算法
根据对象的存活周期,把内存分成多个区域,不同区域使用不同的回收算法回收对象。
Jdk8把堆内存分成以下结构:
新分配的对象不一定分配到 Eden
- 对象大于 -XX:PretenureSizeThreshold , 就会直接分配到老年代。默认值是0,也就是不做限制,单位是字节
- 对象非常的大,新生代的空间不够。会直接放到老年代。 新生代使用的是复制算法,一个超大的对象放在Eden,会造成大量的数据拷贝
对象不一定要达到年龄(15次)才进入老年代
- 还有一个动态年龄判断的规则: 他的大致规则就是,假如说当前放对象的Survivor区域里,一批对象的总大小大于了这块Survivor区域的内存大小的50%,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代了。年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n以上的对象都放入老年代。
新生代使用复制算法,老年代使用标记-整理算法。
分代收集算法的好处
- 更有效的清除不再需要的对象
- 提升了垃圾回收的效率
分代收集算法调优原则
- 合理设置Survivor区域的大小,避免内存浪费
- 让GC尽量发生在新生代,尽量减少Full GC 的发生