﻿<?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-快乐工作，享受生活-文章分类-java编程技术</title><link>http://www.blogjava.net/wangkx/category/26686.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 08 Nov 2007 05:04:49 GMT</lastBuildDate><pubDate>Thu, 08 Nov 2007 05:04:49 GMT</pubDate><ttl>60</ttl><item><title>ClassLoader介绍</title><link>http://www.blogjava.net/wangkx/articles/158518.html</link><dc:creator>柯西</dc:creator><author>柯西</author><pubDate>Tue, 06 Nov 2007 05:46:00 GMT</pubDate><guid>http://www.blogjava.net/wangkx/articles/158518.html</guid><wfw:comment>http://www.blogjava.net/wangkx/comments/158518.html</wfw:comment><comments>http://www.blogjava.net/wangkx/articles/158518.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangkx/comments/commentRss/158518.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangkx/services/trackbacks/158518.html</trackback:ping><description><![CDATA[<p>JVM在运行时会产生三个ClassLoader，Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.其中，Bootstrap是用C++编写的，我们在Java中看不到它，是null。它用来加载核心类库，在JVM源代码中这样写道：<br />
static const char classpathFormat[] =<br />
"%/lib/rt.jar:"<br />
"%/lib/i18n.jar:"<br />
"%/lib/sunrsasign.jar:"<br />
"%/lib/jsse.jar:"<br />
"%/lib/jce.jar:"<br />
"%/lib/charsets.jar:"<br />
"%/classes";<br />
知道为什么不需要在classpath中加载这些类了吧？人家在JVM启动的时候就自动加载了，并且在运行过程中根本不能修改Bootstrap加载路径。<br />
Extension ClassLoader用来加载扩展类，即/lib/ext中的类。<br />
最后AppClassLoader才是加载Classpath的。<br />
ClassLoader加载类用的是委托模型。即先让Parent类(而不是Super，不是继承关系)寻找，Parent找不到才自己找。看来ClassLoader还是蛮孝顺的。三者的关系为:AppClassLoader的Parent是ExtClassLoader，而ExtClassLoader的Parent为Bootstrap ClassLoader。加载一个类时，首先BootStrap先进行寻找，找不到再由ExtClassLoader寻找，最后才是AppClassLoader。<br />
为什么要设计的这么复杂呢？其中一个重要原因就是安全性。比如在Applet中，如果编写了一个java.lang.String类并具有破坏性。假如不采用这种委托机制，就会将这个具有破坏性的String加载到了用户机器上，导致破坏用户安全。但采用这种委托机制则不会出现这种情况。因为要加载java.lang.String类时，系统最终会由Bootstrap进行加载，这个具有破坏性的String永远没有机会加载。<br />
我们来看这段代码：<br />
//A.java<br />
public class A{<br />
public static void main(String[] args){<br />
A a=new A();<br />
System.out.println(System.getProperty("java.ext.dirs"));<br />
System.out.println(a.getClass().getClassLoader());<br />
B b=new B();<br />
b.print();<br />
}<br />
}<br />
//B.java<br />
public class B{<br />
public void print(){<br />
System.out.println(this.getClass().getClassLoader());<br />
}<br />
}<br />
1、我们将它放在Classpath中，则打印出<br />
sun.misc.Launcher$AppClassLoader@92e78c<br />
sun.misc.Launcher$AppClassLoader@92e78c<br />
可见都是由AppClassLoader来加载的。<br />
2、我们将其放在%jre%/lib/ext/classes(即ExtClassLoader的加载目录。其加载/lib/ext中的jar文件或者子目录classes中的class文件)中。则会打印出：<br />
sun.misc.Launcher$ExtClassLoader<br />
sun.misc.Launcher$ExtClassLoader<br />
3、我们将A.class放到%jre%/lib/ext/classes中，而将B.class放到classpaht中又会怎么样呢？结果是：<br />
sun.misc.Launcher$ExtClassLoader<br />
Exception in thread "main" java.lang.NoClassDefFoundError:B<br />
at A.main(A.java:6)<br />
怎么会这样呢？这其中有一个重要的问题：A类当然是由ExtClassLoader来加载的，B类要由哪个加载呢？B类要由调用它自己的类的类加载器(真拗口)。也就是说，A调用了B，所以B由A的类加载器ExtClassLoader来加载。ExtClassLoader根据委托机制，先拜托Bootstrap加载，Bootstrap没有找到。然后它再自己寻找B类，还是没找到，所以抛出异常。ExtClassLoader不会请求AppClassLoader来加载!你可能会想：这算什么问题，我把两个类放到一起不就行了？<br />
呵呵，没这么简单。比如JDBC是核心类库，而各个数据库的JDBC驱动则是扩展类库或在classpath中定义的。所以JDBC由Bootstrap ClassLoader加载，而驱动要由AppClassLoader加载。等等，问题来了，Bootstrap不会请求AppClassLoader加载类啊。那么，他们怎么实现的呢？我就涉及到一个Context ClassLoader的问题，调用Thread.getContextClassLoader。</p>
<img src ="http://www.blogjava.net/wangkx/aggbug/158518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangkx/" target="_blank">柯西</a> 2007-11-06 13:46 <a href="http://www.blogjava.net/wangkx/articles/158518.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK5.0垃圾收集优化</title><link>http://www.blogjava.net/wangkx/articles/158358.html</link><dc:creator>柯西</dc:creator><author>柯西</author><pubDate>Mon, 05 Nov 2007 13:22:00 GMT</pubDate><guid>http://www.blogjava.net/wangkx/articles/158358.html</guid><wfw:comment>http://www.blogjava.net/wangkx/comments/158358.html</wfw:comment><comments>http://www.blogjava.net/wangkx/articles/158358.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangkx/comments/commentRss/158358.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangkx/services/trackbacks/158358.html</trackback:ping><description><![CDATA[&nbsp;作者：<a href="http://blog.csdn.net/calvinxiu/"><font color="#669966">江南白衣</font></a>，最新版链接：<a href="http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx"><font color="#669966">http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx</font></a>，版权所有，转载请保留原文链接。
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 原本想把题目更简单的定为--《不要停》的，但还是自己YY一下就算了。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Java开发Server最大的障碍，就是JDK1.4版之前的的串行垃圾收集机制会引起长时间的服务暂停，明白原理后，想想那些用JDK1.3写Server的先辈，不得不后怕。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;好在JDK1.4已开始支持多线程并行的后台垃圾收集算法，JDK5.0则优化了默认值的设置。 </p>
<p><strong>一、参考资料：</strong> </p>
<ol>
    <li><a href="http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html"><font color="#669966">Tuning Garbage Collection with the 5.0 Java Virtual Machine</font></a>&nbsp;官方指南。
    <li><a href="https://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf"><font color="#669966">Hotspot memory management whitepaper</font></a>&nbsp;官方白皮书。
    <li><a href="http://java.sun.com/performance/reference/whitepapers/tuning.html"><font color="#669966">Java Tuning White Paper</font></a> 官方文档。
    <li><a href="http://java.sun.com/docs/hotspot/gc1.4.2/faq.html"><font color="#669966">FAQ about Garbage Collection in the Hotspot&nbsp;</font></a> 官方FAQ，JVM1.4.2。
    <li><a href="http://gceclub.sun.com.cn/java_one_online/2004/TS-1216CHI(USA,2004)/ts1216ch.pdf"><font color="#669966">Java HotSpot 虚拟机中的垃圾收集</font></a>&nbsp;JavaOne2004上的中文ppt
    <li><a href="http://blogs.sun.com/watt/resource/jvm-options-list.html"><font color="#669966">A Collection of JVM Options</font></a>&nbsp;JVM选项的超完整收集。 </li>
</ol>
<p><strong>二、基本概念</strong> </p>
<p><strong>1、堆(Heap)</strong> </p>
<p>JVM管理的内存叫堆。在32Bit操作系统上有1.5G-2G的限制，而64Bit的就没有。 </p>
<p>JVM初始分配的内存由-Xms指定，默认是物理内存的1/64但小于1G。 </p>
<p>JVM最大分配的内存由-Xmx指定，默认是物理内存的1/4但小于1G。 </p>
<p>默认空余堆内存小于40%时，JVM就会增大堆直到-Xmx的最大限制，可以由-XX:MinHeapFreeRatio=指定。 <br />
默认空余堆内存大于70%时，JVM会减少堆直到-Xms的最小限制，可以由-XX:MaxHeapFreeRatio=指定。 </p>
<p>服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小，所以上面的两个参数没啥用。&nbsp; </p>
<p><strong></strong></p>
<p><strong>2.基本收集算法</strong> </p>
<ol>
    <li><strong>复制</strong>：将堆内分成两个相同空间，从根(ThreadLocal的对象，静态对象）开始访问每一个关联的活跃对象，将空间A的活跃对象全部复制到空间B，然后一次性回收整个空间A。<br />
    因为只访问活跃对象，将所有活动对象复制走之后就清空整个空间，不用去访问死对象，所以遍历空间的成本较小，但需要巨大的复制成本和较多的内存。
    <li><strong>标记清除(mark-sweep)：</strong>收集器先从根开始访问所有活跃对象，标记为活跃对象。然后再遍历一次整个内存区域，把所有没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大暂停时间随空间大小线性增大，而且整理后堆里的碎片很多。
    <li><strong>标记整理(mark-sweep-compact)：</strong>综合了上述两者的做法和优点，先标记活跃对象，然后将其合并成较大的内存块。 </li>
</ol>
<p>&nbsp;&nbsp;&nbsp; 可见，没有免费的午餐，无论采用复制还是标记清除算法，自动的东西都要付出很大的性能代价。 </p>
<p><strong>3.分代</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 分代是Java垃圾收集的一大亮点，根据对象的生命周期长短，把堆分为3个代：Young，Old和Permanent，根据不同代的特点采用不同的收集算法，扬长避短也。 </p>
<p><strong>Young(Nursery)，年轻代</strong>。研究表明大部分对象都是朝生暮死，随生随灭的。因此所有收集器都为年轻代选择了复制算法。<br />
&nbsp;&nbsp;&nbsp; 复制算法优点是只访问活跃对象，缺点是复制成本高。因为年轻代只有少量的对象能熬到垃圾收集，因此只需少量的复制成本。而且复制收集器只访问活跃对象，对那些占了最大比率的死对象视而不见，充分发挥了它遍历空间成本低的优点。 </p>
<p>&nbsp;&nbsp;&nbsp; Young的默认值为4M，随堆内存增大，约为1/15，JVM会根据情况动态管理其大小变化。<br />
&nbsp;&nbsp;&nbsp; -XX:NewRatio= 参数可以设置Young与Old的大小比例，-server时默认为1:2，但实际上young启动时远低于这个比率？如果信不过JVM，也可以用-Xmn硬性规定其大小，有文档推荐设为Heap总大小的1/4。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;Young的大小非常非常重要，见&#8220;后面暂停时间优先收集器&#8221;的论述。 </p>
<p>&nbsp;&nbsp;&nbsp; Young里面又分为3个区域，一个Eden，所有新建对象都会存在于该区，两个Survivor区，用来实施复制算法。每次复制就是将Eden和第一块Survior的活对象复制到第2块，然后清空Eden与第一块Survior。Eden与Survivor的比例由-XX:SurvivorRatio=设置，默认为32。Survivio大了会浪费，小了的话，会使一些年轻对象潜逃到老人区，引起老人区的不安，但这个参数对性能并不重要。&nbsp; </p>
<p><strong>Old(Tenured)，年老代</strong>。年轻代的对象如果能够挺过数次收集，就会进入老人区。老人区使用标记整理算法。因为老人区的对象都没那么容易死的，采用复制算法就要反复的复制对象，很不合算，只好采用标记清理算法，但标记清理算法其实也不轻松，每次都要遍历区域内所有对象，所以还是没有免费的午餐啊。 </p>
<p>-XX:MaxTenuringThreshold=设置熬过年轻代多少次收集后移入老人区，CMS中默认为0，熬过第一次GC就转入，可以用-XX:+PrintTenuringDistribution查看。 </p>
<p><strong>Permanent，持久代。</strong>装载Class信息等基础数据，默认64M，如果是类很多很多的服务程序，需要加大其设置-XX:MaxPermSize=，否则它满了之后会引起fullgc()或Out of Memory。 注意Spring，Hibernate这类喜欢AOP动态生成类的框架需要更多的持久代内存。 </p>
<p><strong>4.minor/major collection</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 每个代满了之后都会促发collection，（另外Concurrent Low Pause Collector默认在老人区68%的时候促发)。GC用较高的频率对young进行扫描和回收，这种叫做minor collection<strong>。<br />
</strong>而因为成本关系对Old的检查回收频率要低很多，同时对Young和Old的收集称为major collection。<br />
&nbsp;&nbsp;&nbsp; System.gc()会引发major collection，使用-XX:+DisableExplicitGC禁止它，或设为CMS并发-XX:+ExplicitGCInvokesConcurrent。 </p>
<p><strong>5.小结</strong> </p>
<p>Young -- minor collection -- 复制算法 </p>
<p>Old(Tenured) -- major colletion -- 标记清除/标记整理算法 </p>
<p><strong></strong></p>
<p><strong>三、收集器</strong> </p>
<p><strong>1.古老的串行收集器(Serial Collector)</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 使用 -XX:+UseSerialGC，策略为年轻代串行复制，年老代串行标记整理。 </p>
<p><strong>2.吞吐量优先的并行收集器(Throughput Collector)</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 使用 -XX:+UseParallelGC ，也是JDK5 -server的默认值。策略为：<br />
&nbsp;&nbsp;&nbsp; 1.年轻代暂停应用程序，多个垃圾收集线程并行的复制收集，线程数默认为CPU个数，CPU很多时，可用&#8211;XX:ParallelGCThreads=减少线程数。<br />
&nbsp;&nbsp;&nbsp; 2.年老代暂停应用程序，与串行收集器一样，单垃圾收集线程标记整理。 </p>
<p>&nbsp;&nbsp;&nbsp; 所以需要2+的CPU时才会优于串行收集器，适用于后台处理，科学计算。 </p>
<p>&nbsp;&nbsp;&nbsp; 可以使用-XX:MaxGCPauseMillis= 和 -XX:GCTimeRatio 来调整GC的时间。 </p>
<p><strong>3.暂停时间优先的并发收集器(Concurrent Low Pause Collector-CMS</strong><strong>)</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 前面说了这么多，都是为了这节做铺垫...... </p>
<p>&nbsp;&nbsp;&nbsp; 使用-XX:+UseConcMarkSweepGC，策略为：<br />
&nbsp;&nbsp;&nbsp; 1.年轻代同样是暂停应用程序，多个垃圾收集线程并行的复制收集。<br />
&nbsp;&nbsp;&nbsp;&nbsp;2.年老代则只有两次短暂停，其他时间应用程序与收集线程并发的清除。 </p>
<p><strong>3.1 年老代详述</strong> </p>
<p>&nbsp;&nbsp;&nbsp; 并行(Parallel)与并发(Concurrent)仅一字之差，并行指多条垃圾收集线程并行，并发指用户线程与垃圾收集线程并发，程序在继续运行，而垃圾收集程序运行于另一个个CPU上。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;并发收集一开始会很短暂的停止一次所有线程来开始初始标记根对象，然后标记线程与应用线程一起并发运行，最后又很短的暂停一次，多线程<strong>并行</strong>的重新标记之前可能因为并发而漏掉的对象，然后就开始与应用程序并发的清除过程。可见，最长的两个遍历过程都是与应用程序并发执行的，比以前的串行算法改进太多太多了！！！ </p>
<p>&nbsp;&nbsp;&nbsp; 串行标记清除是等年老代满了再开始收集的，而并发收集因为要与应用程序一起运行，如果满了才收集，应用程序就无内存可用，所以系统默认68%满的时候就开始收集。内存已设得较大，吃内存又没有这么快的时候，可以用-XX:CMSInitiatingOccupancyFraction=恰当增大该比率。 </p>
<p><strong>3.2 年轻代详述</strong> </p>
<p>&nbsp;&nbsp;&nbsp;可惜对年轻代的复制收集，依然必须停止所有应用程序线程，原理如此，只能靠多CPU，多收集线程并发来提高收集速度，但除非你的Server独占整台服务器，否则如果服务器上本身还有很多其他线程时，切换起来速度就..... 所以，搞到最后，暂停时间的瓶颈就落在了年轻代的复制算法上。 </p>
<p>&nbsp;&nbsp;&nbsp; 因此Young的大小设置挺重要的，大点就不用频繁GC，而且增大GC的间隔后，可以让多点对象自己死掉而不用复制了。但Young增大时，GC造成的停顿时间攀升得非常恐怖，比如在我的机器上，默认8M的Young，只需要几毫秒的时间，64M就升到90毫秒，而升到256M时，就要到300毫秒了，峰值还会攀到恐怖的800ms。谁叫复制算法，要等Young满了才开始收集，开始收集就要停止所有线程呢。 </p>
<p><strong>3.3 持久代</strong> </p>
<p>可设置-XX:+CMSClassUnloadingEnabled <code>-XX:+CMSPermGenSweepingEnabled，使CMS收集持久代的类，而不是fullgc，netbeans5.5 performance文档的推荐。</code> </p>
<p><strong>4.增量(train算法)收集器(Incremental Collector)</strong> </p>
<p>已停止维护，&#8211;Xincgc选项默认转为并发收集器。 </p>
<p><strong>四、暂停时间显示</strong> </p>
<p>&nbsp;加入下列参数 (请将PrintGC和Details中间的空格去掉，CSDN很怪的认为是禁止字句）&nbsp; </p>
<p><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />-verbose:gc&nbsp;-XX:+PrintGC Details&nbsp;&nbsp;-XX:+PrintGCTimeStamps </p>
<p>会程序运行过程中将显示如下输出 </p>
<p>&nbsp;9.211: [GC 9.211: [ParNew: 7994K-&gt;0K(8128K), 0.0123935 secs] 427172K-&gt;419977K(524224K), 0.0125728 secs] </p>
<p>&nbsp;显示在程序运行的9.211秒发生了Minor的垃圾收集，前一段数据针对新生区，从7994k整理为0k，新生区总大小为8128k，程序暂停了12ms，而后一段数据针对整个堆。 </p>
<p>对于年老代的收集，暂停发生在下面两个阶段，CMS-remark的中断是17毫秒： </p>
<p>[GC [1 CMS-initial-mark: 80168K(196608K)] 81144K(261184K), 0.0059036 secs]&nbsp; </p>
<p>[1 CMS-remark: 80168K(196608K)] 82493K(261184K),0.0168943 secs] </p>
<p>再加两个参数 -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime对暂停时间看得更清晰。 </p>
<p><strong>五、真正不停的BEA JRockit 与Sun RTS2.0</strong> </p>
<p>&nbsp; &nbsp;Bea的<a href="http://edocs.bea.com/jrockit/webdocs/index.html"><font color="#669966">JRockit 5.0 R27</font></a> 的特色之一是动态决定的垃圾收集策略，用户可以决定自己关心的是吞吐量，暂停时间还是确定的暂停时间，再由JVM在运行时动态决定、改变改变垃圾收集策略。<br />
&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp; 它的Deterministic GC的选项是-Xgcprio: deterministic，号称可以把暂停可以控制在10-30毫秒，非常的牛，一句Deterministic道尽了RealTime的真谛。 不过细看一下文档，30ms的测试环境是1 GB heap 和 平均 &nbsp;30% 的活跃对象(也就是300M)活动对象，2&nbsp;个 Xeon 3.6 GHz&nbsp; 4G内存&nbsp;，或者是4 个Xeon 2.0 GHz，8G内存。 </p>
<p>&nbsp; 最可惜JRockt的license很奇怪，虽然平时使用免费，但这个30ms的选项就需要购买整个Weblogic Real Time Server的license。&nbsp;</p>
<p>&nbsp;&nbsp;其他免费选项，有：</p>
<ul>
    <li>-Xgcprio:pausetime -Xpausetarget=210ms&nbsp;<br />
    &nbsp;&nbsp;因为免费，所以最低只能设置到200ms pause target。&nbsp;200ms是Sun认为Real-Time的分界线。
    <li>-Xgc:gencon<br />
    普通的并发做法，效率也不错。 </li>
</ul>
<p>&nbsp;&nbsp;JavaOne2007上有Sun的 <a href="http://java.sun.com/javase/technologies/realtime/index.jsp"><font color="#669966">Java Real-Time System 2.0</font></a> 的介绍，RTS2.0基于JDK1.5，在Real-Time&nbsp; Garbage Collctor上又有改进，但还在beta版状态，只供给OEM，更怪。 </p>
<p><strong>六、JDK 6.0的改进</strong> </p>
<p>因为JDK5.0在Young较大时的表现还是不够让人满意，又继续看JDK6.0的改进，结果稍稍失望，不涉及我最头痛的年轻代复制收集改良。 </p>
<p><strong>1.年老代的标识-清除收集，并行执行标识</strong><br />
&nbsp; JDK5.0只开了一条收集进程与应用线程并发标识，而6.0可以开多条收集线程来做标识，缩短标识老人区所有活动对象的时间。 </p>
<p><strong>2.加大了Young区的默认大小</strong><br />
默认大小从4M加到16M，从堆内存的1/15增加到1/7 </p>
<p><strong>3.System.gc()可以与应用程序并发执行</strong><br />
使用-XX:+ExplicitGCInvokesConcurrent 设置</p>
<p><strong>七、小结</strong> </p>
<p><strong>1. JDK5.0/6.0</strong></p>
<p>对于服务器应用，我们使用Concurrent Low Pause Collector，对年轻代，暂停时多线程并行复制收集；对年老代，收集器与应用程序并行标记--整理收集，以达到尽量短的垃圾收集时间。 </p>
<p>本着没有深刻测试前不要胡乱优化的宗旨，命令行属性只需简单写为： </p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: #e6e6e6; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; word-break: break-all; padding-top: 4px; border-bottom: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="color: #000000">-server&nbsp;-Xms&lt;heapsize&gt;M&nbsp;-Xmx&lt;heapsize&gt;M&nbsp;-XX:</span><span style="color: #000000">+</span><span style="color: #000000">UseConcMarkSweepGC&nbsp;&nbsp;-XX:+PrintGC Details&nbsp;&nbsp;-XX:+PrintGCTimeStamps </span></div>
</div>
<p>然后要根据应用的情况，在测试软件辅助可以下看看有没有JVM的默认值和自动管理做的不够的地方可以调整，如-xmn 设Young的大小，-XX:MaxPermSize设持久代大小等。 </p>
<p><strong>2. JRockit 6.0&nbsp;R27.2</strong></p>
<p>但因为JDK5的测试结果实在不能满意，后来又尝试了JRockit，总体效果要好些。<br />
&nbsp;JRockit的特点是动态垃圾收集器是根据用户关心的特征动态决定收集算法的，参数如下</p>
<div style="border-right: windowtext 0.5pt solid; padding-right: 5.4pt; border-top: windowtext 0.5pt solid; padding-left: 5.4pt; background: #e6e6e6; padding-bottom: 4px; border-left: windowtext 0.5pt solid; width: 95%; word-break: break-all; padding-top: 4px; border-bottom: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />&nbsp;-Xms&lt;heapsize&gt;M&nbsp;-Xmx&lt;heapsize&gt;M <span style="color: #000000">-Xgcprio</span><span style="color: #800000">:pausetime</span><span style="color: #000000">&nbsp;-Xpausetarget</span><span style="color: #000000">=</span><span style="color: #000000">200ms -XgcReport -XgcPause -Xverbose:memory</span></div>
</div>
<img src ="http://www.blogjava.net/wangkx/aggbug/158358.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangkx/" target="_blank">柯西</a> 2007-11-05 21:22 <a href="http://www.blogjava.net/wangkx/articles/158358.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>