垃圾回收-GC
三个问题
哪些内存需要回收? 什么时候回收? 如何回收?
YoungGC和FullGC:
新生代引发的GC叫YoungGC
老年代引发的GC叫FullGCFullGC会引起整个Jvm的用户线程暂停,待垃圾回收完毕后,才继续运行
引用的定义:
如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表一个引用
对象存活状态:
确定对象“存活”还是“死去”:以下两种算法原理都一样,就是看当前这个对象,是否有引用正在指向它,如果有,就是还有用的,如果没有,就清除
第一种:引用计数算法(已被废弃):
如果当前对象有一个引用正在指向它,则在其对应的计数器上+1,统计完后计数器上为0的就代表没用的对象,进行清除
第二种:根搜索算法(GC Roots):先找到对象,再根据对象去搜索,看有没有引用正指向它,如果有,就是还有用的,如果没有,就清除
永久代的垃圾回收:
永久代回收“性价比”比较低,因为里面放的都是静态的对象,都是有用的,无法回收,就算触发了一次回收,占用内存还是不会变
主要回收 废弃的常量 无用的类 类的所有实例都已经被回收 加载该类的ClassLoader已经被回收 该类的Class对象没有在任何地方被引用堆垃圾回收算法:
1、标记-清除算法
以两种状态个所有对象分类,然后清除掉可回收的部分
特点:
分为“标记”和“清除”两个阶段 标记完成后,统一回收缺点: 效率,标记和清除过程效率都不高 空间,标记清除后会产生大量不连续的内存碎片
2、复制算法
把内存分为ab两块,触发垃圾回收的时候,直接把a里面可用的对象有序的复制到b里面,并清空a(和新生代的原理一样)
特点:
内存分为相等的两块 当一块内存用完,将存活对象复制到另外一块中,原内存一次性清理掉 复制时按照顺序分配内存,无内存碎片问题 新生代使用此算法缺点: 将内存分为两半,利用率低
3、标记-压缩算法
根据标记清除算法改良而来
特点:
先对存活对象进行标记 让所有存活对象向一边移动 清理掉存活对象边界外的所有内存注:老年代使用此算法
4、分代收集算法
当代的商业虚拟机都采用“分代收集”
根据对象的存活周期的不同将内存划分成几块,一般Java堆分为新生代和老年代新生代采用复制算法老年代采用标记-压缩算法
垃圾收集器
以上的所有算法,都只是理念,而垃圾收集器是内存回收算法的具体实现,没有完美的收集器
Jvm不同的区域可以采用不同的垃圾收集器组合,主要有:
1、Serial收集器(串行)单线程收集器
用户线程全部停止(Stop the world) Client模式下,新生代默认收集器 优点:简单、高效2、ParNew收集器(并行)
并行收集器,Serial收集器的多线程版本
Server模式下Jvm默认的新生代收集器 默认开启的垃圾回收线程与cpu核数一致3、CMS收集器(并发)
并发收集器(ConcurrentMarkSweep)
采用了标记-清除算法并发收集、低停顿缺点: 消耗cpu 会产生内存碎片 浮动垃圾(Concurrent Mode Failure4、G1收集器