GC和分代回收算法
GC(垃圾回收)
GC做的事情就是实现无用的对象内存自动释放,减少内存碎片,加快分配速度。
1.垃圾回收的区域是堆内存,不包括虚拟机栈,因为在虚拟机栈里方法调用结束会自动释放方法所占用的内存
2.判断无用对象,可以使用可达性算法、三色标记法标记存活对象,回收未标记算法
3.GC具体的实现称为垃圾回收器
4.GC大都采用了分代回收思想,一类就是对象用完立即就回收(新生代),另外一类就是对象会长时间的存活(老年代),不同区域回收策略不一样,新生代使用标记复制算法,老年代使用标记整理算法。
5. 根据GC的规模可以分为Minor GC、Mixed GC、Full GC
分代回收
新生代
伊甸园 eden,最初对象都分配到这里,与幸存区合并为新生代
幸存区 survivor,当伊甸园内存不足,回收的幸存对象就房贷这里,分为from和to,该区采用复制算法
老年代 old,当幸存区对象熬过几次回收就会晋升到老年代(最多熬15次),或者当内存区内存不足或者大对象会导致提前普及到老年代
GC规模
a.Minor GC 发函俄国在新生代的垃圾回收,暂停时间短
b.Mixed GC新生代+老年代部分区域的垃圾回收,G1收集器特有
c.Full GC新生代+老年代完整垃圾回收,暂停时间长,尽量避免此情况。
三色标记
黑色 - 以标记
沿着根部的引用链,已经找到这个对象了,并且这个对象的内部其他引用都已经处理完成了(其他都是不会回收的)。
灰色 - 标记中(正在处理中)
沿着根部的引用链,已经找到这个对象了,但是对象内部还有一些其他引用还没有处理完
白色 - 未标记
白色就是要被回收了
并发漏标
并发漏标就是垃圾回收线程在做标记的过程中,用户线程把我们的引用关系给改了,一旦改了就会对垃圾回收的标记造成影响
解决方案
他们解决方案就是记录标记过程中的变化
1.Incremental Update 增量更新
只要发生赋值操作,背赋值的对象就会被记录
2.Snapshop At the Beginning ,STAB 原始快照
新增加对象会被记录
被删除引用关系的对象不会记录
垃圾回收器 1.8使用
Paraller GC
由2个垃圾回收器组成,一个生活在新生代,一个生活在老年代
伊甸园 eden内存不足的时候发生Minor GC,标记复制算法,会STW(Stop the world)
old内存不足发生Full,标记整理STW(Stop the world)
该Paraller GC 适合吞吐量(计算)的项目
ConcurrentMarkSweep GC 启用
可以并发标记并发,重新标记时候需要STW,并发清除。采用了标记清除算法。
Failback Full GC(并发失败) 发生STW让 old eden都发生一次彻底的垃圾清理
注重响应时间
G1 GC 1.9使用
响应时间与吐量兼顾。
用的标记复制算法。
划分多个区域,每个区域都可以充当eden,survivor,old ,humongous
新生代回收 enden内存不足 采用标记复制算法 STW
并发标记:old并发标记,重新标记时需要STW
混合收集:并发标记完成,开始混合收集,参与复制的eden survivor,old其中old会根据暂停时间目标,选择部分回收价值高的区域,
什么情况会出现内存溢出,怎解决?
误用线程池会导致内存溢出
解决方案:不要用Executors类的newFixedThreadPool方法,因为他使用的工作队列是一个无界的队列,去使用线程池的构造方法去设置一个有大小限制的队列。
误用缓冲线程池
解决方法:不要用Executors的newCachedThreadPool,解决方法就是自己去使用线程池的构造方法
一次查询太多数据导致内存溢出
解决方案,设置每次查询的数量
动态生成的类太多
类太多了,都没有进行垃圾回收,导致了我们元空间越来越少最后到内存耗尽。解决办法设置生命周期(如static变成局部变量)