GC的标记算法
-
引用计数算法
-
通过判断对象的引用数量来决定对象是否可以被回收
-
每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1
-
任何引用计数为0的对象实例可以被当作垃圾收集
优点:执行效率高,程序执行受影响较小
缺点:无法检测出循环引用的情况,导致内存泄漏
-
-
可达性分析算法(主流)
- 通过判断对象的引用链是否可达来决定对象是否可以被回收
- 可以作为GC Root的对象
- 虚拟机栈中引用的对象(栈帧中的本地变量表)
- 方法区中的常量引用对象
- 方法区中的类静态属性引用的对象
- 本地方法栈中JNI(Native方法)的引用对象
- 活跃线程的引用对象
GC的垃圾回收算法
-
标记-清除算法(Mark and Sweep)(适合垃圾少)
- 标记:从根集合进行扫描,对存活的对象进行标记(可达性分析算法)
- 清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存
-
标记-整理算法(Compacting)(适合垃圾少)
- 标记:从根集合进行扫描,对存活的对象进行标记(可达性分析算法)
- 整理:移动所有存活的对象,且按照内存地址次序依次排列,将末端内存地址以后的内存全部回收(对标记-清除算法的优化,防止内存碎片问题)
-
复制算法(Copying)(适合垃圾多,减少复制的对象数量)
- 将内存分为对象面和空闲面
- 对象在对象面创建
- 存活的对象被从对象面复制到空闲面,此时原先的对象面变为现在空闲面,被复制了对象的原先空闲面变为现在对象面
-
分代收集算法(Generational Collector)
-
以上回收算法的组合拳
-
按照对象生命周期的不同划分区域以采用不同的垃圾回收算法
-
年轻代使用复制算法(年轻代,垃圾多适合复制算法),老年代使用标记整理算法或标记清除算法(老年代,垃圾少适合这两种算法)
-
年轻代使用的算法,也叫Minor GC
-
年轻代的内存分布(Eden区,两个Surrvivor区(from区,to区))
-
对象如何晋升到老年代
- 经历一定Minor次数依然存活的对象
- Survivor区中存放不下的对象
- 新生成的大对象(-XX:+PretenuerSizeThreshold 大于该值直接放进老年代)
-
常用的调优参数
- -XX:SurvivorRatio:Eden和Survivor的比值,默认8:1
- -XX:NewRatio:老年代和年轻代内存大小的比例
- -XX:MaxTenuringThreshold:对象从年轻代晋升到老年代经过GC次数的最大阈值
-
-
老年代使用的算法
- Full GC(新老同时一起GC)和Major GC(老年代GC:标记-整理算法)
- 触发Full GC的条件
- 老年代空间不足
- 永久代空间不足(jdk8前)
- Minor GC 晋升到老年代的平均大小大于老年代的剩余空间
- 调用System.gc()
-
年轻代常见的垃圾收集器
JVM的运行模式
- Server:启动慢,重量级,启动后运行速度快
- Client:启动快,轻量级,启动后较Server运行速度慢
Serial收集器
-XX:+UseSerialGC,复制算法
- 单线程收集,进行垃圾收集时,必须暂停所有工作进程
- 简单高效,Client模式下默认的年轻代收集器
ParNew收集器
-XX:+UseParNewGC,复制算法
- 多线程收集,其余行为、特点和Serial收集器一样
- 属于Server模式下的收集器单核执行效率不如Serial,在多核下执行才有优势
Parallel Scavenge收集器
-XX:+UseParallerel,复制算法
吞吐量=运行代码的时间/(运行代码的时间+垃圾收集时间)
- 比起关注用户线程停顿时间,更关注系统的吞吐量
- 在多核下执行才有优势,Server模式下默认的年轻代收集器
老年代常见的垃圾收集器
Serial Old收集器
-XX:+UseSerialOldGC,标记-整理算法
-
单线程收集,进行垃圾收集时,必须暂停所有的工作线程
-
简单高效,Client模式下默认的老年代收集器
Parallel Old收集器
-XX:+UserParallelOldGC,标记-整理算法
- 多线程,吞吐量优先
CMS收集器
-XX:+UseConcMarkSweepGC,标记-清除算法
新老代集成的垃圾回收器
G1收集器
-XX:+UseG1GC,复制+标记-整理算法
垃圾收集器之间的联系
连线表示可以共用
Java中的引用类型
强引用
- 最普遍的引用:
Object obj=new Object()
- 即使抛出OutOfMemoryError(内存满了)也不会回收具有强引用的对象
- 通过将对象设置为null来弱化引用,使其被回收
软引用(Soft Reference)
- 对象处在有用但非必须的状态
- 只有当内存空间不足时,GC会回收该引用的对象的内存
- 可以用来实现高速缓存
- 同样,软引用可以和一个引用队列(
ReferenceQueue
)联合使用,如果软引用所引用的对象被垃圾回收,Java
虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用(Weak Reference)
- 非必须的对象,比软引用更弱一些
- GC时会被回收
- 被回收的概率也不大,因为GC线程优先级比较低
- 同样,弱引用可以和一个引用队列(
ReferenceQueue
)联合使用,如果弱引用所引用的对象被垃圾回收,Java
虚拟机就会把这个弱引用加入到与之关联的引用队列中。
虚引用(PhantomReference)
- 不会决定对象的生命周期
- 任何时候都可能被垃圾收集器回收
- 跟踪对象被垃圾收集器回收的活动,起哨兵作用
- 必须和引用队列ReferenceQueue联合使用