﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-梧桐</title><link>http://www.blogjava.net/WutongDeath/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 09:29:32 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 09:29:32 GMT</pubDate><ttl>60</ttl><item><title>Java的垃圾回收机制详解和调优</title><link>http://www.blogjava.net/WutongDeath/archive/2008/03/31/189751.html</link><dc:creator>梧桐</dc:creator><author>梧桐</author><pubDate>Mon, 31 Mar 2008 04:34:00 GMT</pubDate><guid>http://www.blogjava.net/WutongDeath/archive/2008/03/31/189751.html</guid><wfw:comment>http://www.blogjava.net/WutongDeath/comments/189751.html</wfw:comment><comments>http://www.blogjava.net/WutongDeath/archive/2008/03/31/189751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/WutongDeath/comments/commentRss/189751.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/WutongDeath/services/trackbacks/189751.html</trackback:ping><description><![CDATA[<strong>　　1.JVM的gc概述</strong><br />
　　<br />
　　gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc，也没有规定gc如何工作。不过常用的jvm都有gc，而且大多数gc都使用类似的算法管理内存和执行收集操作。<br />
　　<br />
　　在充分理解了垃圾收集算法和执行过程后，才能有效的优化它的性能。有些垃圾收集专用于特殊的应用程序。比如，实时应用程序主要是为了避免垃圾收集中断，而大多数OLTP应用程序则注重整体效率。理解了应用程序的工作负荷和jvm支持的垃圾收集算法，便可以进行优化配置垃圾收集器。<br />
　　<br />
　　垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。gc首先要判断该对象是否是时候可以收集。两种常用的方法是引用计数和对象引用遍历。<br />
　　<br />
　　<font color="orange">1.1.引用计数<br />
　　</font><br />
　　引用计数存储对特定对象的所有引用数，也就是说，当应用程序创建引用以及引用超出范围时，jvm必须适当增减引用数。当某对象的引用数为0时，便可以进行垃圾收集。<br />
　　<br />
　　<font color="orange">1.2.对象引用遍历<br />
　　</font><br />
　　早期的jvm使用引用计数，现在大多数jvm采用对象引用遍历。对象引用遍历从一组对象开始，沿着整个对象图上的每条链接，递归确定可到达（reachable）的对象。如果某对象不能从这些根对象的一个（至少一个）到达，则将它作为垃圾收集。在对象遍历阶段，gc必须记住哪些对象可以到达，以便删除不可到达的对象，这称为标记（marking）对象。<br />
　　<br />
　　下一步，gc要删除不可到达的对象。删除时，有些gc只是简单的扫描堆栈，删除未标记的未标记的对象，并释放它们的内存以生成新的对象，这叫做清除（sweeping）。这种方法的问题在于内存会分成好多小段，而它们不足以用于新的对象，但是组合起来却很大。因此，许多gc可以重新组织内存中的对象，并进行压缩（compact），形成可利用的空间。<br />
　　<br />
　　为此，gc需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止，只有gc运行。结果，在响应期间增减了许多混杂请求。另外，更复杂的 gc不断增加或同时运行以减少或者清除应用程序的中断。有的gc使用单线程完成这项工作，有的则采用多线程以增加效率。<br />
　　<br />
　　<strong>2.几种垃圾回收机制</strong><br />
　　<br />
　　<font color="orange">2.1.标记－清除收集器<br />
　　</font><br />
　　这种收集器首先遍历对象图并标记可到达的对象，然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。<br />
　　<br />
　　<font color="orange">2.2.标记－压缩收集器<br />
　　</font><br />
　　有时也叫标记－清除－压缩收集器，与标记－清除收集器有相同的标记阶段。在第二阶段，则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。<br />
　　<br />
　　<font color="orange">2.3.复制收集器<br />
　　</font><br />
　　这种收集器将堆栈分为两个域，常称为半空间。每次仅使用一半的空间，jvm生成的新对象则放在另一半空间中。gc运行时，它把可到达对象复制到另一半空间，从而压缩了堆栈。这种方法适用于短生存期的对象，持续复制长生存期的对象则导致效率降低。<br />
　　<br />
　　<font color="orange">2.4.增量收集器<br />
　　</font><br />
　　增量收集器把堆栈分为多个域，每次仅从一个域收集垃圾。这会造成较小的应用程序中断。<br />
　　<br />
　　<font color="orange">2.5.分代收集器<br />
　　</font><br />
　　这种收集器把堆栈分为两个或多个域，用以存放不同寿命的对象。jvm生成的新对象一般放在其中的某个域中。过一段时间，继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。<br />
　　<br />
　　<font color="orange">2.6.并发收集器<br />
　　</font><br />
　　并发收集器与应用程序同时运行。这些收集器在某点上（比如压缩时）一般都不得不停止其他操作以完成特定的任务，但是因为其他应用程序可进行其他的后台操作，所以中断其他处理的实际时间大大降低。<br />
　　<br />
　　<font color="orange">2.7.并行收集器<br />
　　</font><br />
　　并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多cpu机器上使用多线程技术可以显著的提高java应用程序的可扩展性。<br />
　　<br />
　　<strong>3.Sun HotSpot</strong><br />
　　<br />
　　1.4.1 JVM堆大小的调整<br />
　　<br />
　　Sun HotSpot 1.4.1使用分代收集器，它把堆分为三个主要的域：新域、旧域以及永久域。Jvm生成的所有新对象放在新域中。一旦对象经历了一定数量的垃圾收集循环后，便获得使用期并进入旧域。在永久域中jvm则存储class和method对象。就配置而言，永久域是一个独立域并且不认为是堆的一部分。<br />
　　<br />
　　下面介绍如何控制这些域的大小。可使用-Xms和-Xmx 控制整个堆的原始大小或最大值。<br />
　　<br />
　　下面的命令是把初始大小设置为128M：<br />
　　<br />
　　java &#8211;Xms128m<br />
　　<br />
　　&#8211;Xmx256m为控制新域的大小，可使用-XX:NewRatio设置新域在堆中所占的比例。<br />
　　<br />
　　下面的命令把整个堆设置成128m，新域比率设置成3，即新域与旧域比例为1：3，新域为堆的1/4或32M：<br />
　　<br />
　　java &#8211;Xms128m &#8211;Xmx128m<br />
　　&#8211;XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize设置新域的初始值和最大值。<br />
　　<br />
　　下面的命令把新域的初始值和最大值设置成64m:<br />
　　<br />
　　java &#8211;Xms256m &#8211;Xmx256m &#8211;Xmn64m<br />
　　<br />
　　永久域默认大小为4m。运行程序时，jvm会调整永久域的大小以满足需要。每次调整时，jvm会对堆进行一次完全的垃圾收集。<br />
　　<br />
　　使用-XX:MaxPerSize标志来增加永久域搭大小。在WebLogic Server应用程序加载较多类时，经常需要增加永久域的最大值。当jvm加载类时，永久域中的对象急剧增加，从而使jvm不断调整永久域大小。为了避免调整，可使用-XX:PerSize标志设置初始值。<br />
　　<br />
　　下面把永久域初始值设置成32m，最大值设置成64m。<br />
　　<br />
　　java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m<br />
　　<br />
　　默认状态下，HotSpot在新域中使用复制收集器。该域一般分为三个部分。第一部分为Eden，用于生成新的对象。另两部分称为救助空间，当Eden 充满时，收集器停止应用程序，把所有可到达对象复制到当前的from救助空间，一旦当前的from救助空间充满，收集器则把可到达对象复制到当前的to救助空间。From和to救助空间互换角色。维持活动的对象将在救助空间不断复制，直到它们获得使用期并转入旧域。使用-XX:SurvivorRatio 可控制新域子空间的大小。<br />
　　<br />
　　同NewRation一样，SurvivorRation规定某救助域与Eden空间的比值。比如，以下命令把新域设置成64m，Eden占32m，每个救助域各占16m：<br />
　　<br />
　　java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2<br />
　　<br />
　　如前所述，默认状态下HotSpot对新域使用复制收集器，对旧域使用标记－清除－压缩收集器。在新域中使用复制收集器有很多意义，因为应用程序生成的大部分对象是短寿命的。理想状态下，所有过渡对象在移出Eden空间时将被收集。如果能够这样的话，并且移出Eden空间的对象是长寿命的，那么理论上可以立即把它们移进旧域，避免在救助空间反复复制。但是，应用程序不能适合这种理想状态，因为它们有一小部分中长寿命的对象。最好是保持这些中长寿命的对象并放在新域中，因为复制小部分的对象总比压缩旧域廉价。为控制新域中对象的复制，可用-XX:TargetSurvivorRatio控制救助空间的比例（该值是设置救助空间的使用比例。如救助空间位1M，该值50表示可用500K）。该值是一个百分比，默认值是50。当较大的堆栈使用较低的 sruvivorratio时，应增加该值到80至90，以更好利用救助空间。用-XX:maxtenuring threshold可控制上限。<br />
　　<br />
　　为放置所有的复制全部发生以及希望对象从eden扩展到旧域，可以把MaxTenuring Threshold设置成0。设置完成后，实际上就不再使用救助空间了，因此应把SurvivorRatio设成最大值以最大化Eden空间，设置如下：<br />
　　<br />
　　java &#8230; -XX:MaxTenuringThreshold=0 &#8211;XX:SurvivorRatio＝50000 &#8230;<br />
　　<br />
　　<strong>4.BEA JRockit JVM的使用</strong><br />
　　<br />
　　Bea WebLogic 8.1使用的新的JVM用于Intel平台。在Bea安装完毕的目录下可以看到有一个类似于jrockit81sp1_141_03的文件夹。这就是 Bea新JVM所在目录。不同于HotSpot把Java字节码编译成本地码，它预先编译成类。JRockit还提供了更细致的功能用以观察JVM的运行状态，主要是独立的GUI控制台（只能适用于使用Jrockit才能使用jrockit81sp1_141_03自带的console监控一些cpu及 memory参数）或者WebLogic Server控制台。<br />
　　<br />
　　Bea JRockit JVM支持4种垃圾收集器：<br />
　　<br />
　　<font color="orange">4.1.分代复制收集器<br />
　　</font><br />
　　它与默认的分代收集器工作策略类似。对象在新域中分配，即JRockit文档中的nursery。这种收集器最适合单cpu机上小型堆操作。<br />
　　<br />
　　<font color="orange">4.2.单空间并发收集器<br />
　　</font><br />
　　该收集器使用完整堆，并与背景线程共同工作。尽管这种收集器可以消除中断，但是收集器需花费较长的时间寻找死对象，而且处理应用程序时收集器经常运行。如果处理器不能应付应用程序产生的垃圾，它会中断应用程序并关闭收集。<br />
　　<br />
　　分代并发收集器这种收集器在护理域使用排它复制收集器，在旧域中则使用并发收集器。由于它比单空间共同发生收集器中断频繁，因此它需要较少的内存，应用程序的运行效率也较高，注意，过小的护理域可以导致大量的临时对象被扩展到旧域中。这会造成收集器超负荷运作，甚至采用排它性工作方式完成收集。
   <img src ="http://www.blogjava.net/WutongDeath/aggbug/189751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/WutongDeath/" target="_blank">梧桐</a> 2008-03-31 12:34 <a href="http://www.blogjava.net/WutongDeath/archive/2008/03/31/189751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>