jvm详解-gc策略
1960年诞生在MIT的lisp是最早使用内存动态分布和垃圾回收技术的语言,但本文主要讲解基于sun hotspot的jvm内存管理机制。内存区域中程序计数器,虚拟机栈,本地方法栈三个区域的声明周期和线程相同,方法的执行和退出的同时,栈中的栈帧会执行入栈和出栈的操作,每一个栈帧分配的内存也是可以在类结构推算出来的,因此这几个内存区域的内存分配,回收是具有确定性的,不需要过多考虑内存回收问题
1960年诞生在MIT的lisp是最早使用内存动态分布和垃圾回收技术的语言,但本文主要讲解基于sun hotspot的jvm内存管理机制。
内存区域中程序计数器,虚拟机栈,本地方法栈三个区域的声明周期和线程相同,方法的执行和退出的同时,栈中的栈帧会执行入栈和出栈的操作,每一个栈帧分配的内存也是可以在类结构推算出来的,因此这几个内存区域的内存分配,回收是具有确定性的,不需要过多考虑内存回收问题
java堆和方法区因为接口会有多种实现,方法会有多种分支,只有在执行期间才能知道具体会创建哪些对象,这部分内存的分配和回收是动态的,垃圾收集器关注的就是这部分。
java是如何判断对象是否存活:
java没有使用引用计数法来进行对象是否存活的判断,而是采用根搜索算法(c#,lisp也是)
根搜索算法:
确定一系列的GC Root的对象作为起点,从这些节点向下搜索,搜索的路径称为引用链(Reference Chain),当一个对象无法通过引用链连向GC Root的话证明此对象是不可用的
GC Root的确定:
1 虚拟机栈中引用的对象
2 方法区中的类静态属性引用的对象
3 方法区中常量引用的属性
4 本地方法栈中Native方法的引用的对象
java如何回收不再存活的对象:
如果一个对象在搜索后发现没有与GC Roots相连接的引用链,就会被第一次标记并且进行一次筛选,看此对象是否有必要执行finalize()方法,如果finalize方法没有被覆盖或者已经被虚拟机调用过了则将此对象删掉,否则此对象将被放入一个名为F-Queue的队列之中,虚拟机会自动建立一条低优先级的Finalizer线程去执行这个对象的finalize方法,如果此次执行该对象还没有与GC Roots建立引用链则会在下次gc的时候被删除。
方法区的回收:
hotspot中方法区的回收主要有两部分:废弃常量和无用的类
回收废弃常量:与堆内对象的回收类似
回收无用的类的条件:
1 堆中不存在该类的任何实例
2 加载该类的ClassLoader被回收
3 该类对应的java.lang.Class对象没有被引用(无法通过反射访问该类)
在大量使用反射,动态代理,cglib等框架以及动态生成jsp和osgi这类频繁自定义ClassLoader的场景需要虚拟机具备类卸载的功能,hotspot可以通过-Xnoclassgc参数进行控制
hotspot垃圾回收算法:
在新生代中使用复制算法:即将内存分为大小相等的2块,每次使用其中一块当一块的内存满了就将其中存活的内存复制到另一块上,然后将使用过的内存全部清理掉
在老年代中使用
1 标记-清除:标记所有需要回收的对象,标记完后统一回收掉被标记的对象
2 标记-整理:标记所有需要回收的对象,让所有存活的对象向一端移动,最后清理掉端边界以外的内存
hotspot包含的所有收集器:
Serial:单线程收集器,Client模式下默认新生代收集器(可与CMS配合使用),使用复制算法,停顿时间优先
优点:对于单个cpu的环境没有线程交互的开销,可以获取最高的单线程收集效率
缺点:进行垃圾回收的时候必须暂停其他所有工作线程
ParNew:Serial的多线程版本,Server模式下新生代收集器,使用复制算法,停顿时间优先
优点:在多个cpu的情况下效率高于Serial,默认收集线程数为cpu数量
缺点:进行垃圾回收的时候必须暂停其他所有工作线程
Parallel Scavenge:多线程,使用复制算法,吞吐量优先使用,GCTimeRatio配置吞吐量
优点:在多个cpu的情况下效率高于Serial,默认收集线程数为cpu数量,对cpu的利用率高
缺点:停顿时间较长
Serial old:已经很少用
Parallel Old:已经很少用
CMS:基于标记-清除,最少停顿时间优先
步骤:
1 初始标记-CMS initial mark(stop the world)
2 并发标记-CMS concurrent mark
3 重新标记-CMS remark(stop the world)
4 并发清除-CMS concurrent sweep
优点:并发收集,低停顿
缺点:
1 并发执行阶段占用cpu资源,会导致应用程序变慢
2 在cms运行期间剩余的内存不足以程序的需要,会出现Concurrent Mode Failure-》会启动Serial Old进行老生代的垃圾收集
3 由于是标记-清除算法,所以收集结束时会产生大量空间碎片可通过-XX:+UseCMSCompaceAtFullCollection来配置Full gc后进行碎片整理
G1:Garbage First:采用标记-整理算法实现
通过减小垃圾区域的粒度,将整个java堆划分为多个大小固定的region,根据优先列表和允许的收集时间优先收集垃圾最多的区域
分配策略:
大多情况对象优先在Eden区分配
大对象直接进入旧生代
长期存活的对象进入旧生代
更多推荐
所有评论(0)