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

来源:互联网 发布:禁止用户安装软件无效 编辑:程序博客网 时间:2024/06/03 13:51
一、概述
内存回收,分析出所以然,为什么如此设计,内存回收,如整理屋子。用户就是系统,其实和普通的系统没有大区别。
需求:
正确
高效(不能对用户线程有较大的影响)
二、设计
我来设计的话,一些基本的问题。
哪些对象需要被回收?
谁来回收? 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

原创粉丝点击