JAVA内存管理(五)HotSpot中的垃圾收集之概述

雪域幽狐 2013-12-18 20:40 阅读:5860


本系列文章由作者@hunter129翻译,转载请注明出处。

很多公司都有自己的JVM实现,被Oracle收购的sun公司开发的JVM实现名为HotSpot。这一实现是我们最常用到的。

还有哪些JVM实现呢?比较有名的有Oracle之前收购的BEA公司(就是以前做WebLogic的那家公司)的JRockit,IBM公司的J9 VM等。还有个半像不像的Dalvik(Goolge开发的运行在android上那玩意)

当然不知名的还有很多,你可以参考这个列表了解下:http://en.wikipedia.org/wiki/List_of_Java_virtual_machines

第四章主要介绍在J2SE 5.0 HotSpot JVM中实现的垃圾收集器。总共分为7个小部分:1.HotSpot中的分代,2.垃圾收集的类型,3.快速分配技术,4.串行收集器,5.并行收集器,6.并行压缩收集器,7.并发的标记-清扫(CMS)收集器。
分为5篇分别介绍,第一篇(本篇)作为综述介绍1-3部分,之后每篇介绍一个垃圾收集器。

以下是正文:

第四章 J2SE 5.0 HotSpot JVM中的垃圾收集

自J2SE 5.0 update 6起,Java HotSpot 虚拟机包括四种垃圾收集器。所有的收集器都是代化的。本章描述这些分代和收集的类型,讨论为什么对象的分配通常是快速高效的。然后提供关于每个收集器的详细信息。

HotSpot 中的分代

在Java HotSpot 虚拟机中,内存被组织为3个代:年轻代(young generation)、年老代(old generation)和持久代(permanent generation)。大部分对象最初在年轻分配。年老代保存着几次年轻代收集后仍然存活的对象和一些可能直接分配到年老代的大对象。持久带存放着JVM认为可以简化垃圾收集管理的对象,如类和方法以及他们的描述信息。

年轻代包括一个伊甸(Eden)区加上俩个小的生还者区(survivor spaces),如图2。大部分对象直接分配在伊甸区(Eden)。(上面提到的一些大对象可能直接分配在年老代。)最后一次垃圾收集后生存的对象保存在生还者区,在它们在被认为“足够老”以晋升到年老代之前仍有机会死掉。在任意给定的时间,一个生还者区(在图中标记为From)保存着这些对象,而另一个则是空的,直到下次垃圾收集前也不会使用。


图2 年轻代的内存区域

垃圾收集的类型

当年轻代填满的时候,将执行一个只在这一代的运行的垃圾收集–年轻代垃圾收集(young generation collection)(有时候隶属于一个主收集(minor collection))。当年老代或持久代填满的时候,将执行一个典型的全收集(Full collection)(有时候隶属于一个主收集(minor collection))。换句话说,所有的代都会被收集。通常的,使用针对年轻代设计的算法在年轻代先执行,因为这是在年轻代标记垃圾最有效的算法。之后,收集器指定的年老代收集算法(old generation collection algorithm)在年老代和持久代使用。如果有压缩,每个代分别进行。

有时候,年轻代首先收集完后,年老代太满,以至于存不下从年轻代晋升到年老代的对象。在这种情况下,除了CMS收集器外的其他收集器的年轻代收集算法都不运行,代替它的是,年老代的收集算法将用在整个堆上。(年老代收集算法CMS是一个特列,因为它不能用来收集年轻代)

译注:这里有点绕口,一个收集器(collector)可能包括多个算法(algorithm),一些用于年轻代,一些用于年老代。这里的意思是CMS这种收集器外的其他的收集器会在年轻代使用年老代的收集算法(整个堆自然包括年轻代),由于年老代太满的原因。CMS收集器不这样的原因是因为CMS算法不能用在年轻代。

快速分配

在下面的垃圾收集器描述中你会看到,在很多情况下都存在一个连续的很大的内存块可用于分配对象。用一种被称为空闲指针(bump-the-pointer)的简单技术在这些块上分配内存是很高效的。就是说,前一次分配的痕迹会保留下来,当有一个新的分配请求时,需要做的仅仅是检查新对象是否能够放的下,如果能,则更新指针引用并初始化对象。

对多线程应用程序来说,分配操作必须是线程安全的。如果使用全局锁保证线程安全,会使得到一代的分配成为瓶颈,并会影响性能。代替它的是HotSpot JVM采用一种称为Thread-Local Allocation Buffers(TLABs)的技术。每个线程从自己拥有的缓存(意思是代中很小的一个部分)中分配从而改善了多线程分配的能力。由于线程只能分配对象到自己的TLAB中,利用空闲指针技术在不需要任何的锁的情况下内存分配依然很快。很少发生的同步只有在线程填满了自己的TLAB后申请一个新的的时候才需要。有几个技术用于最大限度的减少由于使用TLAB技术引起的空间浪费。例如,TLABs浪费的Eden空间被分配器控制在不到1%的水平。结合使用TLABs和使用空闲指针的线性分配(linear allocations)使得每次分配都很有效,只需要大概10条本地指令(native instructions)。

0条评论

登陆后可评论