Java中的GC机制

来源:互联网 发布:多媒体平台软件 编辑:程序博客网 时间:2024/06/05 08:50
这是一篇转载自“http://yemengying.com/2016/05/13/jvm-GC/”的一篇很好的关于垃圾回收机制的文章,总结的很到位,非常感谢Giraffe童鞋的贡献,向原文作者致敬!这里只是简单的罗列,跟详细的细节可以仔细的研究下原文,连接如上。Java中的垃圾回收机制1.关键字约定    Young generation –>新生代    Tenured / Old Generation –>老年代    Perm Area –>永久代2.GC机制的核心    在Java中,对象实例都是在堆上创建。一些类信息,常量,静态变量等存储在方法区。堆和方法区都是线程共享的。    GC机制是由JVM提供,用来清理需要清除的对象,回收堆内存。    GC机制将Java程序员从内存管理中解放了出来,可以更关注于业务逻辑。    在Java中,GC是由一个被称为垃圾回收器的守护线程执行的。    在从内存回收一个对象之前会调用对象的finalize()方法。    作为一个Java开发者不能强制JVM执行GC;GC的触发由JVM依据堆内存的大小来决定。    System.gc()和Runtime.gc()会向JVM发送执行GC的请求,但是JVM不保证一定会执行GC。    如果堆没有内存创建新的对象了,会抛出OutOfMemoryError。    3.GC机制正对的是什么对象?    了解GC机制的第一步就是理解什么样的对象会被回收。    当一个对象通过一系列根对象(比如:静态属性引用的常量)都不可达时就会被回收。    简而言之,当一个对 象的所有引用都为null。    循环依赖不算做引用,如果对象A有一个指向对象B的引用,对象B也有一个指向对象A的引用,除此之外,它们没有其他引用,那么 对象A和对象B都、需要被回收(如下图,ObjA和ObjB需要被回收)。

这里写图片描述

    4.在Java开发中,堆内存是如何划分的?Java开发和C语言和C++是最大的区别就是解放了程序员在开发过程中对内存占用率的考虑,完全的交给javaJVM中的GC机制来处理Java中所创建的对象,那么在了解JavaGC机制时必须了解Java中对于堆内存的划分。首先要明确,Java中对象都在堆上创建。Java的JVM为了GC,堆内存分为三个部分,也可以说三代,分别称为新生代,老年代和永久代。其中新生代又进一步分为Eden 区,Survivor 1区和Survivor 2区(如下图)。新创建的对象会分配在Eden区,在经历一次Minor GC后会被移到Survivor 1区,再经历一次Minor GC后会被移到Survivor 2区,直到升至老年代,需要注意的是,一些大对象(长字符串或数组)可能会直接存放到老年代。

这里写图片描述

永久代有一些特殊,它用来存储类的元信息。对于GC是否发生在永久代有许多不同的看法,在我看来这取决于采用的JVM。大家可以通过创建大量的字符串来观察是发生了GC还是抛出了OutOfMemoryError。5.GC算法这个在之前的了解GC还不深入的情况,还是只知道GC一些很基础简单的东西,很少了解关于GC算法的概念和过程。5.1 标记清除算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。该算法的缺点是效率不高并且会产生不连续的内存碎片。

这里写图片描述

5.2 复制算法把内存空间划为两个区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中 的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。优点:实现简单,运行高效。缺点:会浪费一定的内存。一般 新生代采用这种算法。

这里写图片描述

5.3 标记整理算法标记阶段与标记清除算法一样。但后续并不是直接对可回收的对象进行清理,而是让所有存活对象都想一端移动,然后清理。优点是不会造成内存碎片。

这里写图片描述

6.总结    为了分代垃圾回收,Java堆内存分为3代:新生代,老年代和永久代。    新的对象实例会优先分配在新生代,在经历几次Minor GC后(默认15次),还存活的会被移至老年代(某些大对象会直接在老年代分配)。    永久代是否执行GC,取决于采用的JVM。    Minor GC发生在新生代,当Eden区没有足够空间时,会发起一次Minor GC,将Eden区中的存活对象移至Survivor区。Major GC发生在老年代,当升到老年代的对象大于老年代剩余空间时会发生Major GC。    发生Major GC时用户线程会暂停,会降低系统性能和吞吐量。    JVM的参数-Xmx和-Xms用来设置Java堆内存的初始大小和最大值。依据个人经验这个值的比例最好是1:1或者1:1.5。比如,你可以将-Xmx和-Xms都设为1GB,或者-Xmx和-Xms设为1.2GB和1.8GB。    Java中不能手动触发GC,但可以用不同的引用类来辅助垃圾回收器工作(比如:弱引用或软引用)。
0 0
原创粉丝点击