jvm内存区域
一起看下内存区域:
- 虚拟机栈
线程私有,方法被执行时创建栈帧,主要保存方法中的局部变量表、操作数栈、动态链接、方法返回地址。方法调用时入栈,方法返回是出栈清除,不需要GC
- 本地方法栈
与虚拟机栈类似, 不过本地方法栈服务于本地方法调用
- 程序计数器
线程私有,线程获得处理器时间片执行时,从程序计数器取出对应的字节码行号,进行程序运行,不需要GC
- 本地内存
注意java8和java8之前的区别,在j8之前方法区存在堆中,用于储存类信息、常量、静态变量、即时编译器生成的代码等信息,受XX:PermSize控制,存在出现OOM的可能; 在j8之后,该区域迁移到堆外内存中,提升了性能(该区域不再进行gc,不会有stw),因此也不需要GC
注意:j8之后的方法区内存如何回收?在直接内存申请时会创建堆内对象,堆内对象被回收时会将堆外内存对应的地址指针加入队列,清理程序会对队列进行回收
- 堆
堆是对象创建时分配的区域,需要GC
如何识别垃圾
- 引用计数法
原理很简单,记录对象被引用的次数,次数为0时可以回收。
看起来算法很简单,但是实现起来不是那么回事,对于循环引用的对象难以回收,所以jvm并没有采用此算法。
注:不过在redis采用了此类的方法,以后分析redis的时候再一起看这个问题
- 可达性算法
原理:以GC Roots对象为起点,找出它们引用的对象,再以被引用的对象为起点,找出它们引用的对象,依次类推,进行标记,对于其它不在此引用链中的对象,可以进行回收
对于图上的a 和 b就属于可回收对象,但是它们还有一次逃出被回收的机会,jvm在回收时执行对象的finalize方法,在此方法中,如果对象重新加入GC Roots链,则对象不会被回收,但是finalize方法只会执行一次
什么是GC Roots?
- 虚拟机栈中引用的对象
- 方法区中常量引用的对象
- 方法区中静态变量引用的对象
- 本地方法栈中jni引用的对象
回收算法
- 标记清除
可达性算法标记可回收对象--> 进行清除回收
- 复制算法
将内存分为2部分,在一部分中进行分配,回收时,将存活的对象复制到另一部分
- 标记整理
标记清除的升级,标记清除无疑会带来内存碎片,标记整理在回收时将存活的对象向一端移动,回收另一端内存
- 分代回收
将内存分为 新生代、老生代(j8以前有永久代),比例1:2,新生代分为eden/from survivor/to survivor,比例8:1:1
如何回收
a. 新生代发生的gc叫做YGC,老生代发生的GC叫做FGC
b. 创建对象会分配在eden区域,eden区域内存不足时发生ygc,该区域由于大部分对象都是可回收的,因此采用复制算法进行回收
如何晋升老生代
a. 在ygc多次回收后依然存活的对象,晋升老生代
b. 大对象分配直接进入老生代
c. 对于survivor区域相同年龄的对象占用内存超过survivor一半以上时,所有年龄大于此年龄的对象晋升老生代
空间分配担保
在做ygc之前,vm检查是否允许HandlePromotionFailure晋升担保,如果允许,vm检查老生代的连续可用空间是否大于历次ygc晋升的所用空间,如果大于则进行ygc,否则进行fgc
STW
fgc会清理新生代和老生代,并且带来stw。stw是由于vm暂停了除垃圾回收期线程的所有线程
其中fgc带来的stw更长
fgc带来的stw会影响性能,因此需要选取合适的时间执行,这就是SafePoint,有以下几类:
a. 循环的末尾
b. 方法返回前
c. 调用方法之后
d. 抛出异常的位置
回收器
不同的发展阶段,针对不同的分代,产生了一系列回收器
- Serial
单线程垃圾回收器,常用于client模式下
- ParNew
Serial的多线程版本,常用于server模式下,除了Serial外,只有ParNew收集器可以与CMS配合使用
- Parallel Scavenge
目标是可控制吞吐量,因此ParNew常用于用户交互性服务,而此收集器常用于吞吐量优先的服务
- Serial Old
Serial的老生代版本,常用于client模式下。如果用于server模式下,则主要作为cms失败的后备收集器
- Parallel Scavenge Old
与Parallel Scavenge配合使用
- CMS
优先减少stw时间,减少系统停顿,其回收有4个阶段
- 初始标记:标记GC Roots直接关联到的对象,有stw
- 并发标记:标记GC Roots tracing过程
- 重新标记:标记用户线程执行产生的可回收对象,有stw
- 并发回收:与用户线程并行
缺点
- cms回收线程会影响系统吞吐量
- 回收会产生内存碎片,需要设置-XX:CMSFullGCsBeforeCompation来设置回收时进行内存整理
- 回收的过程中,系统内存不足会导致current mode failure,需要使用serial old进行内存回收,带来更长的stw
- G1
并行垃圾收集器,与cms相比起优点在于
- region内采用标记整理算法、region间采用复制算法,不会产生内存碎片
- 可控制的stw时间
stw为啥可控呢?
- g1将内存分为n个大小相同的region
- 跟踪所有region的内存使用情况以及回收价值
- 根据stw的设置,筛选region进行回收