<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>聚沙成塔-小哈的记事薄 &#187; heap</title>
	<atom:link href="http://www.hashei.me/tag/heap/feed" rel="self" type="application/rss+xml" />
	<link>http://www.hashei.me</link>
	<description>一个系统工程师的絮叨</description>
	<lastBuildDate>Tue, 10 Jan 2012 18:03:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		
<!-- Start Of Script Generated By WP-PostViews Plus -->
<script type='text/javascript' src='http://hashei.me/wp-includes/js/jquery/jquery.js?ver=1.3.2'></script>
<script type="text/javascript">
/* <![CDATA[ */
jQuery.ajax({type:'GET',url:'http://hashei.me/wp-content/plugins/wp-postviews-plus/postviews_plus.php',data:'todowppvp=add&type=tag&id=59_1',cache:false,dataType:'script'});
/* ]]> */
</script>
<!-- End Of Script Generated By WP-PostViews Plus -->
	<item>
		<title>Investigating Out of Memory/Memory Leak Problems</title>
		<link>http://www.hashei.me/2009/09/investigating_out_of_memory_and_memory_leak_problems.html?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=investigating_out_of_memory_and_memory_leak_problems</link>
		<comments>http://www.hashei.me/2009/09/investigating_out_of_memory_and_memory_leak_problems.html#comments</comments>
		<pubDate>Tue, 22 Sep 2009 07:46:00 +0000</pubDate>
		<dc:creator>hashei</dc:creator>
				<category><![CDATA[Websphere系列]]></category>
		<category><![CDATA[weblogic]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[heap]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[Memory Leak]]></category>
		<category><![CDATA[OutOfMemory]]></category>

		<guid isPermaLink="false">http://www.hashei.me/2009/09/investigating_out_of_memory_and_memory_leak_problems.html</guid>
		<description><![CDATA[本文原文地址为http://support.bea.com/support_news/product_troubleshooting/Investigating_Out_of_Memory_Memory_Leak_Pattern.html
但现在这个网址已经无法访问，我在Metalink找到这篇文章并与大家分享。文章发表的较早，但是OOM发生的原理和解决的方法不变。文中提到的/3GB参数和垃圾回收日志分析的方法我在《JAVA性能优化—IBM JDK JVM参数设置》和《JAVA性能优化-GC日志分析》都提到过。如果英文的看起来比较麻烦，我google到台湾人做的一份翻译JavaAPsvr_A_200411_MemoryLeak，不过我看着“记忆体”觉得更别扭。
Problem Description
Out Of Memory (OOM) &#8211; An application displays Out of Memory errors due to memory exhaustion, either in java heap or native memory.
Memory Leak &#8211; Constant memory growth in either java heap or native memory, which will eventually end up in out of memory situation. The techniques to debug the memory leak [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight: normal;">本文原文地址为<a href="http://support.bea.com/support_news/product_troubleshooting/Investigating_Out_of_Memory_Memory_Leak_Pattern.html">http://support.bea.com/support_news/product_troubleshooting/Investigating_Out_of_Memory_Memory_Leak_Pattern.html</a></span></p>
<p><span style="font-weight: normal;"><a href="http://support.bea.com/support_news/product_troubleshooting/Investigating_Out_of_Memory_Memory_Leak_Pattern.html"></a>但现在这个网址已经无法访问，我在Metalink找到这篇文章并与大家分享。文章发表的较早，但是OOM发生的原理和解决的方法不变。文中提到的/3GB参数和垃圾回收日志分析的方法我在<a title="IBM JDK优化" href="http://www.hashei.me/2009/05/tuning-the-ibm-jdk.html" target="_blank">《JAVA性能优化—IBM JDK JVM参数设置</a>》和<a title="GC日志分析" href="http://www.hashei.me/2009/06/analyse-the-gc-logs.html" target="_blank">《JAVA性能优化-GC日志分析》</a>都提到过。如果英文的看起来比较麻烦，我google到台湾人做的一份翻译<a href="http://hashei.me/wp-content/uploads/2009/09/JavaAPsvr_A_200411_MemoryLeak.pdf">JavaAPsvr_A_200411_MemoryLeak</a>，不过我看着“记忆体”觉得更别扭。</span></p>
<h3>Problem Description</h3>
<p><strong>Out Of Memory</strong> (OOM) &#8211; An application displays Out of Memory errors due to memory exhaustion, either in java heap or native memory.</p>
<p><strong>Memory Leak</strong> &#8211; Constant memory growth in either java heap or native memory, which will eventually end up in out of memory situation. The techniques to debug the memory leak situations are the same as the out of memory situations.</p>
<h3>Problem Troubleshooting</h3>
<p>Please note that not all of the following items would need to be done. Some issues can be solved by only following a few of the items.</p>
<h3>Quick Links:</h3>
<ul>
<li><a href="#Java">Java heap, Native memory, Process size</a></li>
<li><a href="#Difference">Difference between process address space and physical memory</a></li>
<li><a href="#Why">Why does the OOM problem occur and What does the JVM do in this situation?</a></li>
<li><a href="#Steps">Steps to debug the problem</a>
<ul>
<li><a href="#determine_OOM_type">Determine if Java OOM or Native OOM</a></li>
<li><a href="#Java_OOM">Java OOM</a></li>
<li><a href="#Native_OOM">Native OOM</a></li>
</ul>
</li>
<li><a href="#HP">HP JVM specific tools/tips</a>&gt;</li>
<li><a href="#Jrockit">Jrockit specific features</a></li>
<li><a href="#Bibliography">Bibliography</a></li>
</ul>
<h3><a name="Java"></a></h3>
<p><strong>Java heap</strong> This is the memory that the JVM uses to allocate java objects. The maximum value of java heap memory is specified using <code>�Xmx</code> flag in the java command line. If the maximum heap size is not specified, then the limit is decided by the JVM considering factors like the amount of physical memory in the machine and the amount of free memory available at that moment. It is always recommended to specify the max java heap value.</p>
<p><strong>Native memory</strong> This is the memory that the JVM uses for its own internal operations. The amount of native memory heap that will be used by the JVM depends on the amount of code generated, threads created, memory used during GC for keeping java object information and temporary space used during code generation, optimization etc.</p>
<p>If there is a third party native module, it could also use the native memory. For example, native JDBC drivers allocate native memory.</p>
<p>The max amount of native memory is limited by the virtual process size limitation on any given OS and the amount of memory already committed for the java heap with -<code>Xmx</code> flag. For example, if the application can allocate a total of 3 GB and if the max java heap is 1 GB, then the max possible native memory is approximately 2 GB.</p>
<p><strong>Process size</strong> Process size will be the sum of the java heap, native memory and the memory occupied by the loaded executables and libraries. On 32 bit operating systems, the virtual address space of a process can go up to 4 GB. Out of this 4 GB, the OS kernel reserves some part for itself (typically 1 ~ 2 GB). The remaining is available for the application.</p>
<p>Windows ：By default, 2 GB is available for the application and 2 GB is reserved for Kernel&#8217;s use. However, on some variants of Windows, there is a /3GB switch which can be used to change this ratio such that the application gets 3 GB. More details on the /3GB switch can be found at:</p>
<p><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/4gt_ram_tuning.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/4gt_ram_tuning.asp</a></p>
<p>RH Linux AS 2.1 ： 3 GB is available for the application.</p>
<p>For other operating systems, please refer to the OS documentation for your configuration.</p>
<p><a href="http://www.hashei.me/TEMP/non1536.htm#TOP">Top of Page</a></p>
<p><span id="more-696"></span></p>
<h3><a name="Difference"></a></h3>
<p>Each process gets its own address space. In 32 bit operating systems, this address space will range from 0 to 4 GB. This is independent of the available RAM or swap space in the machine. The total physical memory available on the machine is the sum of RAM and the swap space available on that machine. All the running processes share this physical memory.</p>
<p>The memory address within a process is virtual. The kernel maps this virtual address to the physical address. The physical address points to a location somewhere in the physical memory. At any given time, the sum of all the virtual memory used by the running processes in a machine cannot exceed the total physical memory available on that machine.</p>
<p><a href="http://www.hashei.me/TEMP/non1536.htm#TOP">Top of Page</a></p>
<h3><a name="Why"></a></h3>
<h4>Out of memory in java heap</h4>
<p>The JVM throws java out of memory (java OOM) error if it is not able get more memory in java heap to allocate more java objects. The JVM cannot allocate more java objects if the java heap is full of live objects and it is not able to expand the java heap anymore.</p>
<p>In this situation, the JVM lets the application decide on what to do after throwing the java.lang.OutOfMemoryError. For example, the application may handle this error and decide to shut down itself in a safe way or decide to run ignoring this error. If the application doesn&#8217;t handle this error, then the thread that throws this error will exit (you will not see this thread if you take a java thread dump).</p>
<p>In case of weblogic server, this error is handled if it is thrown by an execute thread and the error is logged. If this error is being thrown continuously, then the core health monitor thread shuts down the weblogic server.</p>
<h4>Out of memory in native heap</h4>
<p>The JVM throws native out of memory (native OOM) if it is not able to get any more native memory. This usually happens when the process reaches the process size limitation on that OS or the machine runs out of RAM and swap space.</p>
<p>When this happens, the JVM handles the native OOM condition, logs a message saying that it ran out of native memory or unable to acquire memory and exits. If the JVM or any other loaded module (like libc or a third party module) doesn&#8217;t handle this native OOM situation, then the OS will send a sigabort signal to the JVM which will make the JVM exit. Usually, the JVMs will generate a core file when it gets a sigabort signal.</p>
<p><a href="http://www.hashei.me/TEMP/non1536.htm#TOP">Top of Page</a></p>
<h3><a name="Steps"></a></h3>
<h4><a name="determine_OOM_type"></a>Determine whether it is a Java OOM or Native OOM</h4>
<ul>
<li>If the stdout/stderr message says that this is a java.lang.OutOfMemoryError, then this is Java OOM</li>
<li>If the stdout/stderr message says that it failed to acquire memory, then this is a Native OOM</li>
</ul>
<p>Please note that the above messages goes to stdout or stderr and not to the application specific log files like weblogic.log</p>
<p><a href="http://www.hashei.me/TEMP/non1536.htm#TOP">Top of Page</a></p>
<h4><a name="Java_OOM"></a>For Java OOM:</h4>
<ol>
<li><strong>Collect and analyze the verbose gc output</strong>
<ol>
<li><strong>Add &#8220;<code>-verbosegc" </code> flag in the java command line</strong>. This will print GC activity info to stdout/stderr. Redirect the stdout/stderr to a file. Run the application until the problem gets reproduced.</li>
<li><strong>Make sure that the JVM does the following before throwing java OOM</strong><strong>Full GC run:</strong>Does a full GC and all the un-reachable, phantomly, weakly and softly reachable objects are removed and those spaces are reclaimed. More details on different levels of object reachability can be found at:<a href="http://java.sun.com/developer/technicalArticles/ALT/RefObj">http://java.sun.com/developer/technicalArticles/ALT/RefObj</a>
<p>You can check whether full GC was done before the OOM message. A message like the following is printed when a full GC is done (format varies depending on the JVM , Check JVM help message to understand the format)</p>
<p>[memory ] 7.160: GC 131072K-&gt;130052K (131072K) in 1057.359 ms</p>
<p>The format of the above output follows (Note: the same format will be used throughout this Pattern):</p>
<p>[memory ] &lt;start&gt;: GC &lt;before&gt;K-&gt;&lt;after&gt;K (&lt;heap&gt;K), &lt;total&gt; ms<br />
[memory ] &lt;start&gt; &#8211; start time of collection (seconds since jvm start)<br />
[memory ] &lt;before&gt; &#8211; memory used by objects before collection (KB)<br />
[memory ] &lt;after&gt; &#8211; memory used by objects after collection (KB)<br />
[memory ] &lt;heap&gt; &#8211; size of heap after collection (KB)<br />
[memory ] &lt;total&gt; &#8211; total time of collection (milliseconds)</p>
<p>However, there is no way to conclude whether the soft/weak/phantomly reachable objects are removed using the verbose messages. If you suspect that these objects are still around when OOM was thrown, contact the JVM vendor.</p>
<p>If the garbage collection algorithm is a generational algorithm (gencopy or gencon in case of Jrockit and the default algorithm in case of other JDKs), you will also see verbose output something like this:</p>
<p>[memory ] 2.414: Nursery GC 31000K-&gt;20760K (75776K), 0.469 ms</p>
<p>The above is the nursery GC (or young GC) cycle which will promote live objects from nursery (or young space) to old space. This cycle is not important for our analysis. More details on generational algorithms can be found in JVM documentation.</p>
<p>If the GC cycle doesn&#8217;t happen before java OOM, then it is a JVM bug.</p>
<p><strong>Full compaction:</strong></p>
<p>Make sure that the JVM does proper compaction work and the memory is not fragmented which could prevent large objects being allocated and trigger a java OOM error.</p>
<p>Java objects need the memory to be contiguous. If the available free memory is fragmented, then the JVM will not be able to allocate a large object, as it may not fit in any of the available free chunks. In this case, the JVM should do a full compaction so that more contiguous free memory can be formed to accommodate large objects.</p>
<p>Compaction work involves moving of objects (data) from one place to another in the java heap memory and updating the references to those objects to point to the new location. JVMs may not compact all the objects unless if there is a need. This is to reduce the pause time of GC cycle.</p>
<p>We can check whether the java OOM is due to fragmentation by analyzing the verbose gc messages. If you see output similar to the following where the OOM is being thrown even whether there is free java heap available, then it is due to fragmentation.</p>
<p>[memory ] 8.162: GC 73043K-&gt;72989K (131072K) in 12.938 ms<br />
[memory ] 8.172: GC 72989K-&gt;72905K (131072K) in 12.000 ms<br />
[memory ] 8.182: GC 72905K-&gt;72580K (131072K) in 13.509 ms<br />
java.lang.OutOfMemoryError</p>
<p>In the above case you can see that the max heap specified was 128MB and the JVM threw OOM when the actual memory usage is only 72580K. The heap usage is only 55%. Therefore, the effect of fragmentation in this case is to throw OOM even when there is 45% of free heap. This is a JVM bug or limitation.You should contact the JVM vendor.</li>
</ol>
</li>
<li><strong>If the JVM does its work properly</strong> (all the things mentioned in the above step), then the java OOM could be an application issue. The application might be leaking some java memory constantly, which may cause this problem. Or, the application uses more live objects and it needs more java heap memory. The following things can be checked in the application:
<ul>
<li><strong>Caching in the application</strong> &#8211; If the application caches java objects in memory, then we should make sure that this cache is not growing constantly. There should be a limit for the number of objects in the cache. We can try reducing this limit to see if it reduces the java heap usage.Java soft references can also be used for data caching as softly reachable objects are guaranteed to be removed when the JVM runs out of java heap.</li>
<li><strong>Long living objects</strong> &#8211; If there are long living objects in the application, then we can try reducing the life of the objects if possible. For example, tuning HTTP session timeout will help in reclaiming the idle session objects faster.</li>
<li><strong>Memory leaks</strong> : One example of memory leak is when using database connection pools in application server. When using connection pools, the JDBC statement and resultset objects must be explicitly closed in a finally block. This is due to the fact that calling close() on the connection objects from pool will simply return the connection back to the pool for re-use and it doesn&#8217;t actually close the connection and the associated statement/resultset objects.It is recommended to follow the coding practices suggested in the following documents to avoid memory leaks in your application.JDBC &#8211; <a href="http://e-docs.bea.com/wls/docs81/jdbc/troubleshooting.html#1026696">http://e-docs.bea.com/wls/docs81/jdbc/troubleshooting.html#1026696</a>JNDI &#8211; <a href="http://e-docs.bea.com/wls/docs81/jndi/jndi.html#472853">http://e-docs.bea.com/wls/docs81/jndi/jndi.html#472853</a>
<p>JMS &#8211; <a href="http://e-docs.bea.com/wls/docs81/jms/implement.html#1194127">http://e-docs.bea.com/wls/docs81/jms/implement.html#1194127</a></li>
<li><strong>Increase the java heap</strong> &#8211; We can also try increasing the java heap if possible to see whether that solves the problem.</li>
<li>Workaround &#8211; As a temporary work around, the application may be gracefully re-started when the java heap usage goes about 90%. When following this work around, the java max heap can be set to as high as possible so that the application will take more time to fill all the java heap. The java heap usage can be monitored by adding &#8216;-verbosegc&#8217; flag in the java command line which will send the GC/ heap usage info to stdout or stderr.</li>
</ul>
</li>
<li><strong>If none of the above suggestion is applicable to the application</strong>, then we need to use a JVMPI (JVM Profiler Interface) based profiler like Jprobe or OptimizeIt to find out which objects are occupying the java heap. The profilers also give details on the place in the java code from where these objects are being created. This document doesn&#8217;t cover the details on each profiler. The profiler documentation can be referred to understand how to set and start the application with this profilers. In general, JVMPI based profilers have high overhead and drastically reduce the performance of the application. Therefore, it is not advisable to use these profilers in production environments.<a href="http://www.borland.com/optimizeit">http://www.borland.com/optimizeit</a><a href="http://www.quest.com/jprobe">http://www.quest.com/jprobe</a></li>
</ol>
<p><a href="http://www.hashei.me/TEMP/non1536.htm#TOP">Top of Page</a></p>
<h4><a name="Native_OOM"></a>For Native OOM Problem</h4>
<ol>
<li><strong>Collect the following information:</strong>
<ol>
<li><code><strong>�verbosegc</strong></code> output to monitor the java heap usage. This will help to understand the java memory requirement for this application.It should be noted that independent of the actual java heap usage by the application, the amount of max heap specified (using <code>�Xmx</code> flag in the java command line) is reserved at the JVM startup and this reserved memory is not available for any other purpose.In case of Jrockit, use <code>-verbose</code> instead of <code>-verbosegc</code> as this gives codegen information in addition to GC information.</li>
<li><strong>Record the process virtual memory size</strong> periodically from the time the application was started until the JVM runs out of native memory. This will help to understand whether the process really hits the size limitation on that OS.In case of Windows, use the following procedure to monitor the virtual process size:
<ol>
<li>
<ol>
<li>In the Start -&gt; Run\dialog, enter &#8220;perfmon&#8221; and click OK.</li>
<li>In the &#8220;Performance&#8221; window that pops up, click on the &#8220;+&#8221; button (above the graph).</li>
<li>Select the following options in the resulting dialog:
<ul>
<li>Performance object: Process (not the default Processor)</li>
<li>Select counter from list: Virtual Bytes</li>
<li>Select instances from list: Select the JVM (java) instance</li>
<li>Click &#8220;Add&#8221;, then &#8220;Close&#8221;</li>
</ul>
</li>
</ol>
</li>
<p>In case of Unix or Linux, for a given PID, the virtual memory size can be found using this command : <code>ps -p &lt;PID&gt; -o vsz</code>.</p>
<p>In case of Linux, each java thread within a single JVM instance is shown as a separate process. It is enough if we take the PID of the root java process. The root java process can be found using the <code>�forest</code> option for<code>ps</code> command. For example, <code>ps �lU &lt;user&gt; --forest</code> will give a ASCII tree art for all the processes started by the specified user. You can find the root java from the tree art.</ol>
</li>
</ol>
</li>
<li><strong>Memory availability in the machine</strong>If the machine doesn&#8217;t have enough RAM and swap space, then the OS will not be able to give more memory to this process that could also result in out of memory. Make sure that the sum of RAM and swap space in the disk is sufficient to cater to all the running processes in that machine.</li>
<li><strong>Tuning java heap</strong>If the java heap usage is well within the max heap, then reducing the java max heap will give more native memory to the JVM. This is not a solution but a workaround that can be tried. Since the OS limits the process size, we need to strike a balance between the java heap and the native heap.</li>
<li><strong>Native memory usage by the JVM</strong>The amount of native memory usage by the JVM is expected to flatten out after all the classes are loaded and the methods have been called (code generation is over). This usually happens within the first few hours for most of the applications. After that, the JVM uses only little native memory that may be due to run time class loading, code generation due to optimization etc.In order to narrow down the problem, try disabling run time optimizations and check whether that makes any difference.
<ul>
<li>In case of Jrockit, <code>-Xnoopt</code> flag can be used to disable run time optimizations.</li>
<li>In case of SUN hotspot JVM, <code>-Xint</code> flag will force the JVM to run in interpreted mode (no code generation).</li>
</ul>
<p>If the native memory usage continues to grow constantly throughout the run, then this could be a memory leak in the native code.</li>
<li><strong>Third party native modules or JNI code in the application</strong>Check whether you are using any third party native module like database drivers. These native modules could also allocate native memory and the leak may be from these modules. In order to narrow down the problem, you should attempt to reproduce the problem without these third party modules. For example, you can use pure java drivers instead of native database drivers.Check whether your application uses some JNI code. This could also be causing native memory leak and you can try to run the application without the JNI code if possible.</li>
<li><strong>If the source of native memory cannot be found after the above steps</strong>, then you need to work with the JVM vendor to get a special build which can trace the native memory allocation calls and give more information about the leak.</li>
</ol>
<p><a href="http://www.hashei.me/TEMP/non1536.htm#TOP">Top of Page</a></p>
<h3><a name="HP"></a></h3>
<p>The following URL gives some tools and tips specific to OOM situations with HP JVM: <a href="http://www.hp.com/products1/unix/java/infolibrary/prog_guide/diag_memory_leaks.html">HP JVM tools/tips</a></p>
<h3><a name="Jrockit"></a></h3>
<p>Jrockit 8.1 SP1 and above supports JRA recording (Java Runtime Analyzer). This is useful to gather information at JVM run time which will give information about the application like, number of GCs running, number of soft/weak/phantom references, hot methods etc. It is useful to make a recording for few minutes and analyze the data if the JVM has performance problems or hang problems. More details on this can be found in Jrockit docs.</p>
<p><a href="http://edocs.bea.com/wljrockit/docs142/usingJRA/jra.html">http://edocs.bea.com/wljrockit/docs142/usingJRA/jra.html</a></p>
<h3><a name="Bibliography"></a></h3>
<ul>
<li><a href="http://java.sun.com/">Sun Java Web Site</a></li>
<li><a href="http://forum.java.sun.com/">Sun Java Newsgroups</a></li>
<li><a href="http://edocs.bea.com/wljrockit/docs81/index.html">JRockit Documentation</a></li>
<li><a href="http://dev2dev.bea.com/products/wljrockit81/index.jsp">dev2dev (JRockit)</a></li>
<li><a href="news://newsgroups.bea.com/jrockit.developer.interest.general">JRockit newsgroup</a></li>
</ul>
<hr /><small>  Copyright &copy; 2008 This feed is for personal, non-commercial use only<br />
<a href=www.hashei.com >聚沙成塔-小哈的记事薄</a> by hashei 
如果喜欢，欢迎订阅<a href=feed.hashei.com >feed.hashei.com</a><br />
Digital Fingerprint:
 10f920a9f2bae51c3c73c4f5fb50a949</small>]]></content:encoded>
			<wfw:commentRss>http://www.hashei.me/2009/09/investigating_out_of_memory_and_memory_leak_problems.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>JVM的恩恩怨怨-WebSphere性能优化（二）</title>
		<link>http://www.hashei.me/2009/05/gc-performance-tuning.html?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=gc-performance-tuning</link>
		<comments>http://www.hashei.me/2009/05/gc-performance-tuning.html#comments</comments>
		<pubDate>Mon, 18 May 2009 14:44:44 +0000</pubDate>
		<dc:creator>hashei</dc:creator>
				<category><![CDATA[Websphere系列]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[gc]]></category>
		<category><![CDATA[gcpolicy]]></category>
		<category><![CDATA[heap]]></category>
		<category><![CDATA[JVM]]></category>
		<category><![CDATA[performance tuning]]></category>
		<category><![CDATA[内存优化]]></category>

		<guid isPermaLink="false">http://www.hashei.me/2009/05/gc-performance-tuning.html</guid>
		<description><![CDATA[WebSphere优化中不得不提的是对JVM的优化，OutOfMemory、GC时间太长太频繁、内存碎片、大对象问题……虽说JVM运行效率如何很大程度是和代码有关，但是恰当的参数设置还是可以避免很多问题。因为在JAVA程序中，垃圾回收（Garbage Collection——GC）是内存发生瓶颈的主要因素（在程序没有问题的情况下）。
但是JVM的优化（也就是优化GC）是一个很令人头疼的活。调整JVM需要根据不同的平台分别对待，如果不了解直接Google一个参数加上无法生效事小，适得其反就不好了。在 Sun ™Solaris™ 和 HP-UX 平台上，WebSphere使用的是Sun和HP提供的JDK，而所有其他平台，WebSphere提供的是IBM JDK。所以优化参数主要区别在IBM JDK和非IBM JDK上，Sun和Hp环境下的优化方案基本能共享。
通用配置
          GC优化的关键是降低频率（frequency）和减少持续时间（duration）。但是两者此消彼长，所以平衡一个恰当的值十分关键。频率和堆的大小和分配增长速度有关，而持续时间则和堆大小和堆中对象的多少有关。由此可以看出最先要考虑的就是堆的大小。
          最大堆、最小堆设置：现在32位的堆，一般设置为256～512M或者512～1024M，但是
       对于不同的应用程序，最优化堆大小的设置都有可能不同。如果堆设置较大，可能导致 GC 的次数变少，但每次 GC 所花的时间很长，从而导致系统的处理能力抖动很大。此外如果堆设置过大，会占用过多的内存，使内存资源耗尽，从而会频繁的进行 IO 操作来使用虚拟内存。 如果堆设置较小，可能导致 GC 变的频繁，但每次 GC 所花的时间不会太长，每次 GC 对系统的性能影响相对也会小些。但是如果堆设置过小， 会使得对象可分配空间变小，从而会频繁的 GC 来释放内存空间，而每次 GC，都会耗用一定的系统资源。因此，要通过试验和监控数据，设法使的我们所设置的堆大小能够使得系统运行最优化。
          具体合适的值，可以启用-verbose:gc来观察。一般良好的堆大小，要让回收频率保持在10秒左右，而一次的full gc回收时间在1到2秒之内（一般的回收时间更短才好）。要注意的是，对于32位的JDK，在Windows环境下单个堆不要超过1.7G，AIX平台不要超过3.2G。下面摘自 出色的“清洁工具” ― 理解 IBM Java 垃圾收集器，第一部分：: 对象分配
 



问题
建议措施


在堆达到稳定状态以前，GC 的频率太高。
使用 verbosegc 确定处于稳定状态的堆大小并将 -Xms 设置成这个值。


堆被完全扩展并且占用率大于 70%。
增加 -Xmx 值使堆占用率不超过 70%。为了获取最佳性能，尝试确保堆从不换页。物理内存应该能容纳最大的堆大小（如果可能）。


占用率为 70% 时，GC 的频率过大。
更改 -Xminf 的设置。缺省值是 0.3，它将通过扩充堆来尝试维持 30% [...]]]></description>
			<content:encoded><![CDATA[<p style="text-indent: 24pt">WebSphere优化中不得不提的是对JVM的优化，OutOfMemory、GC时间太长太频繁、内存碎片、大对象问题……虽说JVM运行效率如何很大程度是和代码有关，但是恰当的参数设置还是可以避免很多问题。因为在JAVA程序中，垃圾回收（Garbage Collection——GC）是内存发生瓶颈的主要因素（在程序没有问题的情况下）。</p>
<p style="text-indent: 24pt">但是JVM的优化（也就是优化GC）是一个很令人头疼的活。调整JVM需要根据不同的平台分别对待，如果不了解直接Google一个参数加上无法生效事小，适得其反就不好了。在 Sun ™Solaris™ 和 HP-UX 平台上，WebSphere使用的是Sun和HP提供的JDK，而所有其他平台，WebSphere提供的是IBM JDK。所以优化参数主要区别在IBM JDK和非IBM JDK上，Sun和Hp环境下的优化方案基本能共享。</p>
<h4>通用配置</h4>
<p>          GC优化的关键是降低频率（frequency）和减少持续时间（duration）。但是两者此消彼长，所以平衡一个恰当的值十分关键。频率和堆的大小和分配增长速度有关，而持续时间则和堆大小和堆中对象的多少有关。由此可以看出最先要考虑的就是堆的大小。</p>
<p>          最大堆、最小堆设置：现在32位的堆，一般设置为256～512M或者512～1024M，但是</p>
<blockquote><p>       对于不同的应用程序，最优化堆大小的设置都有可能不同。如果堆设置较大，可能导致 GC 的次数变少，但每次 GC 所花的时间很长，从而导致系统的处理能力抖动很大。此外如果堆设置过大，会占用过多的内存，使内存资源耗尽，从而会频繁的进行 IO 操作来使用虚拟内存。 如果堆设置较小，可能导致 GC 变的频繁，但每次 GC 所花的时间不会太长，每次 GC 对系统的性能影响相对也会小些。但是如果堆设置过小， 会使得对象可分配空间变小，从而会频繁的 GC 来释放内存空间，而每次 GC，都会耗用一定的系统资源。因此，要通过试验和监控数据，设法使的我们所设置的堆大小能够使得系统运行最优化。</p></blockquote>
<p>          具体合适的值，可以启用-verbose:gc来观察。一般良好的堆大小，要让回收频率保持在10秒左右，而一次的full gc回收时间在1到2秒之内（一般的回收时间更短才好）。要注意的是，对于32位的JDK，在Windows环境下单个堆不要超过1.7G，AIX平台不要超过3.2G。下面摘自 <a title="出色的“清洁工具” ― 理解 IBM Java 垃圾收集器，第一部分：: 对象分配" href="http://www.ibm.com/developerworks/cn/java/i-garbage1/" target="_blank">出色的“清洁工具” ― 理解 IBM Java 垃圾收集器，第一部分：: 对象分配</a></p>
<p> </p>
<table border="0" cellspacing="0" cellpadding="2" width="616">
<tbody>
<tr>
<td width="254" valign="top"><strong>问题</strong></td>
<td width="360" valign="top"><strong>建议措施</strong></td>
</tr>
<tr>
<td width="254" valign="top">在堆达到稳定状态以前，GC 的频率太高。</td>
<td width="360" valign="top">使用 verbosegc 确定处于稳定状态的堆大小并将 -Xms 设置成这个值。</td>
</tr>
<tr>
<td width="254" valign="top">堆被完全扩展并且占用率大于 70%。</td>
<td width="360" valign="top">增加 -Xmx 值使堆占用率不超过 70%。为了获取最佳性能，尝试确保堆从不换页。物理内存应该能容纳最大的堆大小（如果可能）。</td>
</tr>
<tr>
<td width="254" valign="top">占用率为 70% 时，GC 的频率过大。</td>
<td width="360" valign="top">更改 -Xminf 的设置。缺省值是 0.3，它将通过扩充堆来尝试维持 30% 可用空间。设置为 0.4 将可用空间目标增加到 40%，从而降低 GC 的频率。</td>
</tr>
<tr>
<td width="254" valign="top">暂停时间过长。</td>
<td width="360" valign="top">尝试使用 -Xgcpolicy:optavgpause （在 1.3.1 中引入），它在堆占用增加时减少暂停时间并且使它们更一致。在吞吐量方面要付出代价。代价是变化的，大约在 5% 左右。</td>
</tr>
</tbody>
</table>
<p>确定了堆大小，接下来要考虑的是</p>
<h4>GC的策略</h4>
<p style="text-indent: 24pt">IBM JDK（1.5）下WebSphere首先要了解的是<strong><a title="垃圾收集策略" href="http://www.ibm.com/developerworks/cn/java/j-ibmjava2/" target="_blank">4个Policy</a></strong>：</p>
<blockquote><p><em>IBM SDK 5.0 中的 GC 策略</em></p>
<p>针对吞吐量进行优化<br />
<code>-Xgcpolicy:optthruput</code>（可选）<br />
默认策略。对于吞吐量比短暂的 GC 停顿更重要的应用程序，通常使用这种策略。每当进行垃圾收集时，应用程序都会停顿。</p>
<p>针对停顿时间进行优化<br />
<code>-Xgcpolicy:optavgpause</code><br />
通过并发地执行一部分垃圾收集，在高吞吐量和短 GC 停顿之间进行折中。应用程序停顿的时间更短。</p>
<p>分代并发<br />
<code>-Xgcpolicy:gencon</code><br />
以不同方式处理短期存活的对象和长期存活的对象。采用这种策略时，具有许多短期存活对象的应用程序会表现出更短的停顿时间，同时仍然产生很好的吞吐量。</p>
<p>子池 （一般平台用不到）<br />
<code>-Xgcpolicy:subpool</code><br />
采用与默认策略相似的算法，但是采用一种比较适合多处理器计算机的分配策略。建议对于有 16 个或更多处理器的 SMP 计算机使用这种策略。这种策略只能在 IBM pSeries® 和 zSeries® 平台上使用。需要扩展到大型计算机上的应用程序可以从这种策略中受益。</p></blockquote>
<p style="text-indent: 24pt">其中optthruput是默认的IBM JDK GC策略，我觉得不是很适合一般电子商务的情况。因为它的GC停顿时间是三种策略里最长的，而且对于频繁分配短生命周期、小对象的应用来说，很容易就产生了内存碎片，虽然标志-扫描-紧凑排列（mark-sweep-compact）的第三个阶段“紧凑排列”可以消除碎片，但是这种动作开销很大。一般需要设置P cluster、K cluster参数来减少碎片<a title="Avoiding Java heap fragmentation with Java SDK V1.4.2." href="http://www-01.ibm.com/support/docview.wss?uid=swg21176363" target="_blank">Avoiding Java heap fragmentation with Java SDK V1.4.2.</a> （这个参数在1.5中也适用）</p>
<p style="text-indent: 24pt">optavgpause是以一点吞吐量的牺牲（官方说是5%）换来响应时间的提高，用并发标记（JDK1.4）外加并发扫描（JDK1.5引入）的方式来减少GC “Stop the world”的时间。</p>
<p style="text-indent: 24pt">但一般而言，我都是设置成<code>-Xgcpolicy:gencon</code> ，gencon就是我们常说的“分代回收”策略，在HP和SUN的JDK实现中是默认的回收策略。这篇文章<a title="Java 理论与实践: JVM 1.4.1 中的垃圾收集" href="http://www.ibm.com/developerworks/cn/java/j-jtp11253/" target="_blank">Java 理论与实践: JVM 1.4.1 中的垃圾收集</a>，介绍的就是分代回收策略，而且肯定是针对SUN的JDK，当然HP的也适用。可以关注下面这张图：</p>
<p style="text-indent: 24pt"><a href="http://www.ibm.com/developerworks/cn/java/j-jtp11253/images/gc-options.gif" target="_blank"><img src="http://www.ibm.com/developerworks/cn/java/j-jtp11253/images/gc-options.gif" alt="" width="543" height="227" /></a></p>
<p style="text-indent: 24pt">形象直观，文章里的文字总忘掉七零八落，但那些原理可以日后巩固，这幅图保存好了设置参数就没啥大问题。</p>
<p style="text-indent: 24pt">注意下图显示的IBM JDK的分代回收参数设置和SUN/HP的不同</p>
<p style="text-indent: 24pt"><a href="http://hashei.me/wp-content/uploads/2009/05/jvm2.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" src="http://hashei.me/wp-content/uploads/2009/05/jvm-thumb2.jpg" border="0" alt="jvm" width="566" height="225" /></a></p>
<p style="text-indent: 24pt">IBM没有设置MaxPermSize的地方，这点要注意了。</p>
<p style="text-indent: 24pt"><strong>HP和SUN的JDK也有两种主要的回收策略</strong>，分别是对应高吞吐率的-XX:+UseParallelGC和快速响应时间的-XX:+UseConcMarkSweepGC。</p>
<p style="text-indent: 24pt">本文主要是描述GC优化的纲领，指出不同的JDK优化对策的不同。详细的参数测试有待以后慢慢写。</p>
<h4>相关阅读：</h4>
<p style="text-indent: 24pt"><a title="Java 技术，IBM 风格: IBM Developer Kit 简介" href="http://www.ibm.com/developerworks/cn/java/j-ibmjava1.html" target="_blank">Java 技术，IBM 风格: IBM Developer Kit 简介</a></p>
<p style="text-indent: 24pt"><a title="Java 理论与实践: 垃圾收集简史" href="http://www.ibm.com/developerworks/cn/java/j-jtp10283/" target="_blank">Java 理论与实践: 垃圾收集简史</a>  可以了解为什么不同的回收策略，表现出的gc时间会如此迥异。虽然<a title="Java 技术，IBM 风格: 垃圾收集策略，第 1 部分" href="http://www.ibm.com/developerworks/cn/java/j-ibmjava2/" target="_blank">Java 技术，IBM 风格: 垃圾收集策略，第 1 部分</a>一文也叙述的很详细，但是个人觉得《垃圾回收简史》一文写的更明了，毕竟这是最原始的设计，省略了实现过程中添加的许多特性。</p>
<hr /><h2>Related posts:</h2><ul><li><a href="http://www.hashei.me/2009/07/java-performance-tuning-resources.html" rel="bookmark" title="Permanent Link: Java性能优化参考资料">Java性能优化参考资料</a></li><li><a href="http://www.hashei.me/2010/05/linux-system-performance-monitoring.html" rel="bookmark" title="Permanent Link: Linux 性能监控">Linux 性能监控</a></li><li><a href="http://www.hashei.me/2009/05/adjust-proper-pool-size.html" rel="bookmark" title="Permanent Link: 你需要多大的池？&mdash; WebSphere性能优化（一）">你需要多大的池？&mdash; WebSphere性能优化（一）</a></li><li><a href="http://www.hashei.me/2009/12/java_performance_slides.html" rel="bookmark" title="Permanent Link: 两个关于JAVA性能优化的PPT">两个关于JAVA性能优化的PPT</a></li><li><a href="http://www.hashei.me/2009/05/code-optimization-for-gc.html" rel="bookmark" title="Permanent Link: JAVA性能优化&mdash;编写符合GC胃口的程序">JAVA性能优化&mdash;编写符合GC胃口的程序</a></li></ul><hr /><small>  Copyright &copy; 2008 This feed is for personal, non-commercial use only<br />
<a href=www.hashei.com >聚沙成塔-小哈的记事薄</a> by hashei 
如果喜欢，欢迎订阅<a href=feed.hashei.com >feed.hashei.com</a><br />
Digital Fingerprint:
 10f920a9f2bae51c3c73c4f5fb50a949</small>]]></content:encoded>
			<wfw:commentRss>http://www.hashei.me/2009/05/gc-performance-tuning.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

