GC与内存分配
判断对象死亡?
引用计数器(了解)
原理
给对象添加一个应用计数器,有引用+1,没引用-1
难以解决对象之间循环引用问题
可达性分析算法(GC_Root)\
原理
通过一系列的称为"GC ROOTS"的对象做为起始点,从这个节点开始向下搜索,
搜索所走过的路径称为引用链(Reference Chain)
当一个对象到GC_Root没有任何引用链相连(也就是从GC Roots到这个对象不可达)
则证明这个对象不可用
GC Roots
虚拟机栈(栈帧中的本地变量表)中的引用对象
方法区中类静态属性引用对象
方法区中常量引用对象
本地方法栈中JNI(Native方法)引用的对象
补充知识
如何描述这一类:内存足够的时候,希望保留在内存,内存不够的时候,抛弃这些对象
Strong Reference 强引用 Soft Reference 软引用 Weak Reference 弱引用 Phantom Reference 虚引用
生存还死亡?
如果对象在进行可达分析后没有发现GC Roots连接的引用链,
则会被第一次标记,且进行一次筛选,筛选条件是此对象是否有必要执行finalize(),
当对象没有覆盖finalize()活着finalize()已经被虚拟机调用过,则虚拟机认为没必要执行??what
如果有必要finalize(),
则把这个对象放在一个F-Queue,并稍后由一个虚拟机 的 Finalizer线程去执行他的 finalize()
finalize()是对象逃脱死亡命运的 最后一次机会,稍后GC对F-Queue中的对象进行第二次小规模标记,
只要对象在finalize()中拯救自己,即可避免回收
扩展知识
安全点
垃圾收集算法
标记_清除算法
标记->清除
不足:
1.效率问题:标记和清除两个过程效率都不高
2.空间问题:标记清楚之后会产出大量的空间碎片
复制算法
原理
讲内存等分两份,每次只使用其中一份,当使用的这块内存用完了,就想这个内存上的对象复制到另一块上,然后清空
有点:
效率高
不足:
内存只能使用原来的一半
新生代
新生代采用此算法
8:1:1
| eden | survivor_to | survivor_from |
每次只是用eden和survior中的一块,当回收时,直接讲使用的两块复制到另一块未使用的survivor
可见回次回收的都是不多于10%的对象,可以存活
新生代:老年代 默认比例 1:3
当survior空间内存不够,需要依赖其他内存,也就是老年代的内存担保
标记-整理算法
复制收集算法在对象存活比例较高的时候要进行较多的复制操作,效率将会变低
更关键的是,如果不想浪费50%的空间,就需要额外的空间进行分配担保,所以老年代不能采用这种
根据老年代的特点,提出了 "标记-整理":
标记之后让所有存活的对象向一段 端移动,然后直接清理掉端边界外的内存.
垃圾收集器
概览
新生代垃圾回收器
1.Serial垃圾收集器
采用串行单线程的方式完成GC 任务,Stop the Word!
采用复制算法:
young generation 标记-复制
old generation 标记-整理
适合客户端模式
2.ParNew
是Serial的多线程版本,需要线程切换,依旧Stop the word!
多核CUP的情况下,比Serial高效!缩短GC时间
3.Parallel Scavenge
Parallel Scavenge和parNew一样都是并行的多线程的新生代收集器,都使用"复制"算法进行垃圾回收
也称"吞吐量优先"收集器
异常点:
ParNew收集器追求降低GC时用户停顿的时间,适合交互式应用,良好的反应速度提升用户体验
Paraller Scavenge追求可控的CPU 吞吐量,能够在较短的时间完成指定的内容,适合不需要太多交互的后台运算
吞吐量:用户线程运行时间/CPU总时间(用户线程运行时间+GC线程运行时间)
可以自适应调节策略
老年代垃圾回收
1.Serial Old
Serial的老年代版本,使用"标记-整理"算法,主要应用Client模式下
2.Parallel Old
Parallel Scavenge的老年代版本
3.CMS
低延迟:用户线程和GC线程并发执行
由于CMS采用"标记-清除"算法,因此会产生大量的空间碎片.为解决这个问题
-XX:+UserCMSCompactAtFullCollection
强制JVM在FGC完成后对老年代压缩,执行一次空间碎片 整理,同时会引发STW
-XX:+CMCFullGCsBeforeCompaction=n
执行n次FGC后,JVM再在老年代执行空间碎片整理
CMS过程:
过程:
->初始标记 STW
->并发标记
->重新标记
->并发标记
CMS缺点:
- 由于CMS在GC过程用户GC线程并行,从而有线程的额外开销
- 内存碎片化的问题
- 无法处理浮动垃圾,导致频繁FGC
4.G1
提供了三种垃圾回收模式:YoungGC MixGC FullFC,在不同条件下触发 设计原则就是简化jvm性能调优
- 开启G1收集器
- 设置堆的最大内存
- 设置最大的停顿时间
Humongous区域:存放巨型对象(>50% region)
原理
最大的区别是取消了年轻代,老年代的物理划分,取而代之的是将堆分为若干区域
内存分配
内存分配规则
对象优先在Eden分配,如果Eden没有足够空间进行分配.虚拟机将发起一次MinorGC
如果这个MinorGC发现 survivor空间不够,无法放入,则 通过 分配担保 转移到老年代
老年代不够,则majorGC
补充
- 1.大对象直接进入老年代
- 2.长期存活的对象晋级到老年代
- 3.动态对象年龄判定{如果Survivor空间中相同年龄的所有对象的大小等于Survivor的一般,年龄等于活着大于的对象可以之间进入老年代}
- 4.空间分配担保: HandlePromotionFailure(允许风险,则minorGC,不允许,直接FullGC)