Java垃圾回收机制

Java垃圾回收机制

http://my.oschina.net/xinxingegeya/blog/337305

回到正题,咱们继续谈垃圾回收,在学习GC之前,你首先应该记住一个单词:“stop-the-world”。Stop-the-world会在任何一种GC算法中发生。Stop-the-world意味着 JVM 因为要执行GC而停止了应用程序的执行。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态,直到GC任务完成。GC优化很多时候就是指减少Stop-the-world发生的时间。


按代的垃圾回收机制

在Java程序中不能显式地分配和注销内存。有些人把相关的对象设置为null或者调用System.gc()来试图显式地清理内存。设置为null至少没什么坏处,但是调用System.gc()会显著地影响系统性能,必须彻底杜绝(还好,我还没有见到NHN的哪个开发者调用这个方法)。


在Java中,开发人员无法直接在程序代码中清理内存,而是由垃圾回收器自动寻找不必要的垃圾对象,并且清理掉他们。垃圾回收器会在下面两种假设(hypotheses)成立的情况下被创建(称之为假设不如改为推测(suppositions)或者前提(preconditions))。

  1. 大多数对象会很快变得不可达

  2. 只有很少的由老对象(创建时间较长的对象)指向新生对象的引用

这些假设我们称之为弱年代假设( weak generational hypothesis)。为了强化这一假设,HotSpot虚拟机将其物理上划分为两个–新生代(young generation)和老年代(old generation)。

新生代(Young generation): 绝大多数最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可到达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为”minor GC“。


老年代(Old generation): 对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。其所占用的空间要比新生代多。也正由于其相对较大的空间,发生在老年代上的GC要比新生代少得多。对象从老年代中消失的过程,我们称之为”major GC“(或者”full GC“)

如下图所示,

Java垃圾回收机制_第1张图片

请看下面这个图表。

Java垃圾回收机制_第2张图片

图1 : GC 空间 & 数据流

http://my.oschina.net/xinxingegeya/blog/337305

-XX:NewRatio

-XX:NewRatio=ratio

Sets the ratio between young and old generation sizes. By default, this option is set to 2. The following example shows how to set the young/old ratio to 1:

-XX:NewRatio=1

-XX:SurvivorRatio

-XX:SurvivorRatio=ratio

Sets the ratio between eden space size and survivor space size. By default, this option is set to 8. The following example shows how to set the eden/survivor space ratio to 4:

-XX:SurvivorRatio=4

上图中的永久代( permanent generation )也被称为方法区(method area)(http://my.oschina.net/xinxingegeya/blog/209497)。他用来保存类常量以及字符串常量。因此,这个区域不是用来永久的存储那些从老年代存活下来的对象。这个区域也可能发生GC。并且发生在这个区域上的GC事件也会被算为major GC。


新生代的构成

为了更好地理解GC,我们现在来学习新生代,新生代是用来保存那些第一次被创建的对象,他可以被分为三个空间

  1.  一个伊甸园空间(Eden )

  2.  两个幸存者空间(Survivor )

一共有三个空间,其中包含两个幸存者空间。每个空间的执行顺序如下:

  1. 绝大多数刚刚被创建的对象会存放在伊甸园空间。

  2. 在伊甸园空间执行了第一次GC之后,存活的对象被移动到其中一个幸存者空间。

  3. 此后,在伊甸园空间执行GC之后,存活的对象会被堆积在同一个幸存者空间。

  4. 当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。之后会清空已经饱和的那个幸存者空间。

  5. 在以上的步骤中重复几次依然存活的对象,就会被移动到老年代。

如果你仔细观察这些步骤就会发现,其中一个幸存者空间必须保持是空的。如果两个幸存者空间都有数据,或者两个空间都是空的,那一定标志着你的系统出现了某种错误。通过频繁的minor GC将数据移动到老年代。

需要注意的是HotSpot虚拟机使用了两种技术来加快内存分配。他们分别是是”bump-the-pointer“和“TLABs(Thread-Local Allocation Buffers)”。


Bump-the-pointer技术跟踪在伊甸园空间创建的最后一个对象。这个对象会被放在伊甸园空间的顶部。如果之后再需要创建对象,只需要检查伊甸园空间是否有足够的剩余空间。如果有足够的空间,对象就会被创建在伊甸园空间,并且被放置在顶部。这样以来,每次创建新的对象时,只需要检查最后被创建的对象。这将极大地加快内存分配速度。但是,如果我们在多线程的情况下,事情将截然不同。如果想要以线程安全的方式以多线程在伊甸园空间存储对象,不可避免的需要加锁,而这将极大地的影响性能。TLABs 是HotSpot虚拟机针对这一问题的解决方案。该方案为每一个线程在伊甸园空间分配一块独享的空间,这样每个线程只访问他们自己的TLAB空间,再与bump-the-pointer技术结合可以在不加锁的情况下分配内存。

以上是针对新生代空间GC技术的简要介绍,你不需要刻意记住我刚刚提到的两种技术。不知道他们不会对你产生什么影响,但是请务必记住在对象刚刚被创建之后,是保存在伊甸园空间的。那些长期存活的对象会经由幸存者空间转存在老年代空间。

===========END===========

你可能感兴趣的:(Java垃圾回收机制)