前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM内存回收机制及回收器-一目了然

JVM内存回收机制及回收器-一目了然

作者头像
小小科
发布2018-05-03 11:14:44
5980
发布2018-05-03 11:14:44
举报
文章被收录于专栏:北京马哥教育北京马哥教育

一、概述

内存回收,分析出所以然,为什么如此设计,内存回收,如整理屋子。用户就是系统,其实和普通的系统没有大区别。

需求: 正确 高效(不能对用户线程有较大的影响)

二、设计

我来设计的话,一些基本的问题。 哪些对象需要被回收? 谁来回收? JVM 在哪里回收? 一般堆上,栈上回收比较困难 在什么时候回收? 怎么回收?

第一个问题:

哪些对象需要被回收?

我们需要先标记出来, 大致有两个标记的算法, 第一:引用计算法。就是 引用了就加1,减少一个引用就减1.但是无法解决 互相引用的问题。故JAVA没有采用了。为什么别的语言采取了,我也不知道。 第二:根搜索算法 从根 GC roots开始找,如果是根不可达的对象就是 可回收的对象。JAVA JVM就是采取这种方式实现的。

第二问题:

谁来回收?

那肯定要一个名称,叫垃圾回收器,运行在回收线程里面。垃圾回收器具体要解决什么时候做,如何回收的问题。

第三个问题:在哪里回收?

一般在堆上。栈上回收比较困难,栈上也可以进行内存回收,不过条件太苛刻了。

第四个问题与第五个问题一起回答了:

在什么时候回收? 基本是在内存不够用的时候。每个收集器还所有不同。 垃圾回收基本的思想是:stop-the-world再回收,就如:不能在打扫卫生的时候同时再仍新的垃圾。 但是CMS、与将出世的 G1会打破这个界限,实现 边打扫卫生,还边扔垃圾。

怎么回收:一般有三个基本的算法: 1、标记清除:直接标记,再清除掉需要回收的内存。(产生大量的内存碎片) 2、标记复制:用两个一样的大小的内存,总只有一块再用,回收时没有回收的部分直接复制到另一块上去。 3、标记整理:先标记,让所有存活的对象向一段移动,然后直接清除掉边界外的内存。 java中的处理: 根据对象的存活生命周期将不同的内存分为几块。新生代与老年代 新生代有大量的对象死去,只有少量的对象存活,所以用复制算法。 老年代对象存活周期长,没有额外的担保空间,就必须用 标记清除 与标记整理 的算法。 以下再描述下: 为了解决对象生命周期长短对回收的影响,在hotSpot中主要分为了: young与old区。 young区的大部分对象基本可以回收,所以采取了标记复制算法。(复制算法就是浪费了50%的内存),为了不浪费太多的内存,采取了 两个交换区与一个Eden区。交换区互换地存下每次young gc留下来的对象,如果存不下就需要 old区来担保了(多余的对象直接进入old区)。 old区内存一般停留比较久,内存也比较大,他也找不到担保内存了,也不可能把内存分为两部分互相拷贝。所以一开始就采取了标记整理的算法。(开始一直认为标记清除 算法会产生大量的内存碎片,会很不好,后来回收器设计者的想法可能变了)。 根据线程数为单线程与多线程,追求 目标不同。先后有: young区:Serial(单线程)、parNew(多线程)、Parallel Scavenge(多线程,追求高的CPU吞吐量,与前者的并行是不同的实现)。 Old区:Serial Old(单线程,是Serial的Old版本)、Parallel Old(多线程,追求高的CPU吞吐量,是Parallel Scavenge的Old版本)

问题1:?为什么parNew没有Old的版本呢? 可能是 Parallel Old 已经好用了,没有必要再弄一个parNew Old吧。不过有点牵强。还有原因就是 没有资源弄了,大家都开发g1去了。嘿嘿。。。 问题2:?为什么young区有两个多线程的回收器? 可能是:他们的来源不一样,一个是自己实现的,一个用了部分Exact VM的分代式GC框架的思想。这个也是Parallel Scavenge与CMS不兼容的原因。

CMS(coururrent Mark Sweep)收集器,可以容许 用户线程与回收线程在回收的大部分时间里并行运行。

算法是: 标记清除,因为不需要移动对象的内存,所以实现并发处理相对简单些。 CMS大致的过程是: 初始标记,并发标记(与用户线程并发运行),重新标记,并发清除(与用户线程并发运行)。

在并发清除中,(用户线程还在运行)会产生浮动垃圾,垃圾一多,用户线程不能申请内存时,会产生 Concurrent Mode Failure错误,再会触发一次Serial Old Full GC,这个也是下图:CMS与Serial Old连着的原因.

【 为什么会触发一个 单线程的 full gc呢.估计原因是没有时间做多线程的。 后来把资源投入到了 Garbage Collection的研发上去了。

在jdk7中估计会产生重量级的垃圾回收器Garbage First简称G1。此改进了CMS的内存碎片的问题,把算法由 标记清除,变为了标记整理。主要是 把堆再分为不同的小区,对垃圾较多的优先回收。基本能实现 实时java的垃圾收集器

下图展示了目前jdk1.6的回收器。回收器连线表示可以互相协同作战。旁边有一些参数主要作为调试用。

三、结尾

没有一个垃圾回收器能解决所有的问题,针对不同的场景需要不同的垃圾回收器。单线程的Serial与Serial Old也不是不好,在单CPU下他就是最好的。 也希望JAVA能推出新一代的垃圾回收器,为我们高效低回垃回收内存。

四、参考资料

《深入理解java虚拟机》 Garbage Collection:http://labs.oracle.com/jtech/pubs/#gc

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-03-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 马哥Linux运维 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档