进一步理解java垃圾收集器

作者 chauncy 日期 2016-12-09
进一步理解java垃圾收集器

1)java对象的创建是在java堆(heap)中,如本地变量和成员变量不在此区域。值得注意的是,类变量(static)静态成员的创建是在方法区(method area),方法区和堆区是被各个线程共享。

2)垃圾收集是由Java虚拟机提供了一个机制,它通过回收可以回收的对象,来重新分配堆空间

3)垃圾收集器让java 编程者脱离内存管理,而不是跟c++一样管理内存是每个使用它的必要掌握技能,这样做的目的是为了让我们更加注重业务需求逻辑

4)垃圾收集器在java 中被守护进线程所实现

5)在垃圾收集器回收对象之前,会调用对象的finalize()方法,这样是给我提供在回收对象清理之前,我们可以处以一些收尾的工作

6)作为java 程序员不能强制之行垃圾回收,jvm 会根据堆内存的大小自动执行

7)有类似的方法System.gc()的和Runtime.gc()这是用来发送垃圾收集的请求到JVM的,但它不能保证垃圾回收会发生。

8)如果没有足够的内存来分配给新创建的对象,jvm 会抛出OutOfMemoryError or java.lang.OutOfMemoryError heap space异常。

什么时候对象符合垃圾回收

一个对象如果是不能从任何线程抵达或者没有任何引用那就符合被回收的,或者你可以认为一个对象符合被回收,那么他的引用对象为空,循环引用不作为引用,比如:一个对象A引用一个对象B,同时对象B又引用对象A,对象A和对象B他们都没有其他任何存活的对象引用,那么A ,B都符合被垃圾回收。

符合垃圾回收满足如下:
1) 显式地设置为null如对象,e.g. object = null
2) 一个局部变量(创建一个临时对象)失去作用域
3)父对象设置为null,如果一个对象包含另一个对象的引用,当您设置容器对象的引用为null,子对象或所含对象自动进行垃圾收集
4)如果一个对象仅仅是weak references通过WeakHashMap 他将会被回收

java堆垃圾收集分代
java堆被分成 3个部分,分别是年轻代(young),老年代(old),和永久代(perm),年轻代又被分为3个部分,eden 区,survivor1 survivor2 ,当一个对象第一次被创建,那它将在eden区中,后续进行 minor gc 时候,如果对象还存活,它将从survivor1 移动到survivor2 中如果是在major gc发生时候将存活的对象移 老年代区
堆中的永久带区域存放的是 类和方法的meta data,以及我们承载了我们讨论的String,至于perm 区的回收则取决jvm 的实现平台,如果想判断当前使用的平台是否支持perm区的回收,简单的办法就是创建成千上万很多的String,看gc 是或者看是否有OutOfMemoryError 错误。

java gc的几种类型

SerialGC :Serial 收集器是最基本、 发展历史最悠久的收集器,曾经(在JDK1.3.1之前)是虚拟机新生代收集的唯一选择。大家看名字 就会知道,这个收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是他进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。“stop the world”这个词也许听起来很酷,这项工作时由虚拟机在后台自动发起的,在用户不可见的情况下把用户正常工作的线程全部停掉。并非一无是处,对于限定单个cpu的环境来说,该收集器由于没有线程交互的开销,专心垃圾收集自然可以获得最高的单线程手机效率

ParNew 收集器:ParNew收集器启示就是 serial收集器的多线程版本,除了使用多线程之外,其余行为包括serial 收集器可用的所有控制参数(例如 -XX:SurvivorRatio -XX:PretenureSizeThreshold -XX:HandlePromotionFailure 等),收集算法,Stop The World 等都一样
在继续介绍之前,先做一个名词解释:
paralle 并行,指多条垃圾手机线程并行工作,但此时用户线程仍然处于等待状态
concurrent 并发,指用户线程与垃圾收集线程(但不一定是并行的,可能会交替执行),用户程序继续运行,而垃圾垃圾收集程序运行另外一个CPU

ConcMarkSweepGC:cms收集器是基于“标记-清楚”算法实现的,它的运作过程分为4个步骤:初始标记,并发标记,重新标记,并发清除
其中初始标记,重新标记这两个步骤仍然需要”stop the world”。初始标记仅仅只是标记一下gc roots能直接关联到的对象,数度很快,并发标记阶段就是进行gc roots tracing 的过程,而重新新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记纪录。由于整个过程中耗时最长的并发标记和并发清楚过程收集器线程都可以与用户线程一起工作,所以,从总体来说,cms收集器的内存回收过程是与用户线程一起并发执行的。

Garbage-First:G1能利用多CPU,多核环境下的硬件优势,使用多个CPU来缩短 stop-the-world 停顿时间,部分其他收集器原本需要停顿java线程执行gc动作,g1收集器仍然可以通过并发的方式让java程序继续执行。使用G1收集器它将整个java堆划分为多哥大小相当独立区域(region),虽然还保留新生代和老年代的概念,但新生代和老年代步在时物理隔离的了,他们都是一部分region (不需要连续)的集合,G1在后台维护一个优先队列表,每次根据允许的收集时间,优先回收价值最大的region。
在G1收集器中,Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都使用Rememberd Set 来避免全堆扫描的。G1中每个region都有一个与之对应的Rememberd Set,程序在对references类型的数据 进行写操作时,会产生一个write barrier 暂时中断写操作,检查reference 引用对象是否处于不同的region之中,便通过cardtable把相关引用信息记录到被引用对象所属的region 的Rememberd Set之中,在gc根节点的枚举范围加入 Rememberd set 即可保证不对全堆扫描
G1步骤:初始标记,并发标记,最终标记,筛选回收