<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Heck's  Blog]]></title> 
<link>https://www.heckjj.com/index.php</link> 
<description><![CDATA[一瞬间的决定，往往可以改变很多，事实上，让自己成功的往往不是知识，是精神！ 如果你总是为自己找借口，那只好让成功推迟。执行力，今天！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Heck's  Blog]]></copyright>
<item>
<link>https://www.heckjj.com/post//</link>
<title><![CDATA[JVM的内存模型、（GC）垃圾处理、调优监控(基于HotSpot VM，JDK1.5+)]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[Web开发]]></category>
<pubDate>Sun, 30 Mar 2014 10:03:19 +0000</pubDate> 
<guid>https://www.heckjj.com/post//</guid> 
<description>
<![CDATA[ 
	<span style="font-size: 24px;">一、JVM内存模型概括 <br/></span><br/><a href="https://www.heckjj.com/attachment.php?fid=133" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=133" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>还有一个寄存器，线程运行于其上面<br/><br/><span style="font-size: 14px;"><strong>1.程序计数器</strong> </span><br/>记录线程的执行位置，线程私有内存，唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域<br/><span style="font-size: 14px;"><strong>2.线程栈（VM stack）</strong> </span><br/><a href="https://www.heckjj.com/attachment.php?fid=130" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=130" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>栈的默认大小是1M<br/><br/>-Xss2m 这样设置成2M<br/><br/>异常 ：Fatal: Stack size too small<br/><br/>异常的引起一般是线程数目太多<br/><br/><span style="font-size: 14px;"><strong>3.本地方法栈（native stack）</strong> </span><br/><br/>即为一些Native方法分配的stack<br/><br/>异常：java.lang.OutOfMemoryError: unable to create new native thread<br/><br/>一般也是由线程太多引起，增加栈空间，同上方法<br/><br/><span style="font-size: 14px;"><strong>4.堆(heap)，程序可用堆</strong> </span><br/><br/><a href="https://www.heckjj.com/attachment.php?fid=134" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=134" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>截图自JConsole <br/>每个线程的栈都是该线程私有的，堆则是所有线程共享的<br/><br/>这里说的堆，主要指程序能控制的，包括<br/><br/><a href="https://www.heckjj.com/attachment.php?fid=132" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=132" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/><u>The New Generational Heap</u>，默认4M，此区域一般为JVM内存的1/15大小<br/><br/>此代分为Eden space区，Survivo space区可以看成emptySurvivo区，Survivor区,<br/><br/>当new 一个对象时，首先是在Eden space区，当Eden space区满时，Survivor space区进行垃圾回收（此处复制算法），当对象在Survivo space区经过几次回收Tenured Generation<br/><br/>复制算法，每次算法开始都得停止当前所有的线程，然后把Survivor区的所有活跃的对象复制到emptySurvivo区，然后对Survivor区空间进行清除变成emptySurvivo，以前的emptySurvivo成为了Survivor区。（互换）<br/><br/> <br/><u>Tenured Generation</u>，<br/><br/>此处储存年老代的对象，此处的垃圾回收采用The Mark and Sweep 算法<br/><br/>GC标记算法/清理算法（The Mark and Sweep algorithms）进行回收，从引用进行标记，然后按照引用的程度或无引用到的对象进行回收，然后再对清除了的内存进行合并.<br/> <br/><br/><span style="font-size: 10px;"><strong>关于GC，因为GC主要就是对堆的回收，当然还有常量池和永久代，所以此处总结下GC</strong> </span><br/><br/><u>GC策略介绍</u><br/><br/>对于GC在 HotSpot VM 常用的有三种：<br/><br/><span style="font-size: 10px;"><strong>1.serial collector，单线程收集器，</strong> </span>回收时都需要暂停当前线程，长时间等待，<br/><br/>配置<br/><br/>Client下默认方式<br/><br/>强制加上 -XX:+UseSerialGC<br/><br/><span style="font-size: 12px;"><strong>2.parallel collector( throughput collector )，并行收集器，或叫多线程的收集，</strong> </span><br/><br/>年轻代：暂停应用程序，多个垃圾收集线程并行的复制收集。<br/>年老代：暂停应用程序, 多个垃圾收集线程并行的复制收集。<br/><br/>server下默认方式，具体配置<br/><br/>设置并行收集的线程数目，如20个线程，-XX:ParallelGCThreads=20<br/><br/>配置年轻代为并行收集&nbsp;&nbsp;-XX:+UseParallelGC.<br/><br/>配置年老代垃圾收集方式为并行收集（JDK6.0开始支持）-XX:+UseParallelOldGC<br/><br/>设置暂停时间，设置每次年轻代垃圾回收的最长时间如果无法满足此时间，JVM会自动调整年轻代大小，以满足此值，如 -XX:MaxGCPauseMillis= 100， <br/><br/>设置吞吐量，吞吐量为垃圾回收时间与非垃圾回收时间的比值&nbsp;&nbsp;-XX:GCTimeRatio 来调整GC的时间<br/><br/>3.concurrent collector(concurrent low pause collector)，并发收集器，<br/><br/>年轻代：同样是暂停应用程序，多个垃圾收集线程并行的复制收集。<br/>年老代：和并行的区别在这，只是在初始标记（initial mark）和二次标记（remark）时需要stop-the-world。但收集时时间很长，所以不能等年轻代满后再开始清理.<br/><br/>使用启动并发收集器 -XX:+UseConcMarkSweepGC<br/><br/>XX:CMSInitiatingOccupancyFraction=指定还有多少剩余堆时开始执行并发收集<br/><br/><br/>根据官方文档，他们俩个需要在多CPU的情况下，才能发挥作用。在一个CPU的情况下，会不如默认的serial collector，因为线程管理需要耗费CPU资源。而在两个CPU的情况下，也提高不大。只是在更多CPU的情况下，才会有所提高。当然 concurrent low pause collector有一种模式可以在CPU较少的机器上，提供尽可能少的停顿的模式，见CMS GC Incremental mode。<br/>当要使用throughput collector时，在java opt里加上-XX:+UseParallelGC，启动throughput collector收集。也可加上-XX:ParallelGCThreads=&lt;desired number&gt;来改变线程数。还有两个参数 -XX:MaxGCPauseMillis=&lt;nnn&gt;和 -XX:GCTimeRatio=&lt;nnn&gt;，MaxGCPauseMillis=&lt;nnn&gt;用来控制最大暂停时间，而-XX: GCTimeRatio可以提高GC说占CPU的比，以最大话的减小heap。<br/>- 此段引自 <a href="http://www.cnblogs.com/redcreen/archive/2011/05/04/2037029.html" target="_blank"><span style="color: #4169E1;"><u>HotSpot VM GC 的种类</u></span> </a><br/> <br/><br/>GC的触发条件（基于serial collector，不同的GC策略略有不同，基本都差不多）<br/><br/>对于new generation来说，当eden区的对象空大于Survivor0（假设为from）的free空间时，会发生minor gc，即对整个Survivor0区，Survivor1区进行一个复制算法垃圾回收，并且部分对象转到Old Generation<br/><br/>当new generation满了（即eden区+Survivor0区大于Old Generation的free空间时），将发生major gc，即对New Generation和Old Generation两代都进行垃圾回收<br/><br/>当然还一种程序调用system.gc(),但此方法也不一定会调用，只是建议<br/><span style="color: #FF0000;">所以得出，如果JVM的设置内存过大，发生GC的回收频率将越小，但是回收的时间越长（特别对new generation进行复制算法的复制时是需要停止当前所有线程的），所以并不是说JVM的内存设置的越大越好，得根据实际情况进行优化。</span><br/> <br/><br/>异常 java.lang.OutOfMemoryError: Java heap space<br/><br/>一般是由于垃圾回收后，old generation里空间也不够用了<br/><br/><br/><u>堆内存的相关参数设置</u><br/><br/>默认值（基于-server）<br/><br/>-server时最大堆内存是物理内存的1/4，但小于1G. JDK 1.5以前是64M<br/><br/>（官方： Smaller of 1/4th of the physical memory or 1GB.Before J2SE 5.0, the default maximum heap size was 64MB.）<br/><br/>-client 小一倍<br/><br/>参数设置<br/><br/>-Xms128m <br/>表示JVM Heap(堆内存)最小尺寸128MB，初始分配 <br/>-Xmx512m <br/>表示JVM Heap(堆内存)最大允许的尺寸256MB，按需分配<br/><br/> <br/>new Generation与Old Generation的比例，默认为1:2，即为2<br/><br/>-XX:NewRatio= 参数可以设置（也可以-XX:NewSize和-XX:MaxNewsize设置新域的初始值和最大值）<br/> <br/><br/>Eden与Survivor的比例，默认为32<br/><br/>-XX:SurvivorRation=参数可以设置<br/><br/><br/>当对象默认经过1次New Generation 就转入Old Generation（<span style="color: #FF0000;">这个不同文章上不同，待我确定</span>）<br/><br/>-XX:MaxTenuringThreshold=参数可以设置 （默认0）<br/><br/>用-XX:+PrintTenuringDistributio可以查看值<br/><br/><br/><span style="font-size: 14px;"><strong>5.方法区，永久代（Perm Space）</strong> </span><br/><br/>其实也可与看成堆内存的一部分，看成永久代（Perm Space），但GC也会回收，但很少回收，它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据，比如一个int x，在不同的环境中是不同的，此信息就存在方法区<br/><br/>异常：java.lang.OutOfMemoryError: PermGen space<br/><br/>引起，一般是太多的类信息，比如应用spring很多反射信息，可以适度设置大点<br/><br/><u>方法区或永生代相关设置</u><br/><br/>-XX:PermSize=64MB 最小尺寸，初始分配 <br/>-XX:MaxPermSize=256MB 最大允许分配尺寸，按需分配<br/><br/>XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled 设置垃圾不回收<br/><br/>默认大小<br/><br/>-server选项下默认MaxPermSize为64m <br/>-client选项下默认MaxPermSize为32m<br/><br/> <br/><span style="font-size: 14px;"><strong>6.常量池 </strong> </span><br/>Class文件中除了有类的版本、字段、方法、接口等描述等信息外，还有一项信息是常量表(constant_pool table)，用于存放编译期已可知的常量，这部分内容将在类加载后进入方法区（永久代）存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池，运行期间也可将新内容放入常量池（最典型的String.intern()方法）。<br/><br/>GC的作用主要是用来卸载类和回收常量池，当然有部分方法区，即使永久代（Perm Space）也会一定的回收<br/><br/><br/><span style="font-size: 14px;"><strong>7.native内存区“Code Cache”(non-heap)</strong> </span><br/><br/>这个没画出来，但通过工具可以看到，用于存放编译和保存本地代码（native code）的内存<br/><br/><br/><span style="font-size: 24px;"><strong>二、对TOMCAT监控调优</strong> </span><br/><br/><span style="font-size: 12px;"><strong>1、监控TOMCAT内存</strong> </span><br/><br/>JConsole，JDK自带<br/><br/>直接在命令行输入JConsole，打开JConsole，如堆那个图，就可以监控了<br/><br/>远程监控，需要在启动程序时，配置 com.sun.management.jmxremote 即可<br/><br/>比如tomcat，<br/><br/>打开%tomcat_home%/bin/catalina.bat （linux下是catalina.sh），在JAVA_OPTS=%JAVA_OPTS%后加上参数<br/><br/>-Dcom.sun.management.jmxremote.port=1090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false<br/><br/>然后打开JConsole<br/><br/><a href="https://www.heckjj.com/attachment.php?fid=135" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=135" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>然后连接即可<br/><br/><a href="https://www.heckjj.com/attachment.php?fid=136" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=136" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>如打开堆图，可以找到上面说的各个部分<br/><br/><a href="https://www.heckjj.com/attachment.php?fid=137" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=137" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><a href="https://www.heckjj.com/attachment.php?fid=131" target="_blank"><img src="https://www.heckjj.com/attachment.php?fid=131" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/> <br/><br/>Eden Space (heap)： 内存最初从这个线程池分配给大部分对象。<br/><br/>Survivor Space(heap)：用于保存从Eden Space copy的对象，复制算法，分两部分Survivor<br/><br/>Tenured Generation (heap)：用于保持已经在 survivor space内存池中存在了一段时间的对象。<br/><br/>Perm Generation (non-heap): 方法区，保存虚拟机自己的静态(refective)数据，例如类（class）和方法（method）对象。Java虚拟机共享这些类数据。这个区域被分割为只读的和只写的<br/><br/>Code Cache(non-heap):HotSpot Java虚拟机包括一个用于编译和保存本地代码（native code）的内存，叫做“代码缓存区”（code cache）<br/><br/><span style="font-size: 12px;"><strong>2、打印Tomcat的日志</strong> </span><br/><br/>在前面继续加上参数 -Xloggc:%TOMCAT_HOME%&#92;logs&#92;tomcat_gc.log&nbsp;&nbsp;， 把LOG日志文件输出到tomcat_gc.log <br/><br/>打开日志如下<br/><br/>0.755: [GC 11747K-&gt;1664K(62848K), 0.0039655 secs]<br/>0.759: [Full GC 1664K-&gt;1604K(<br/>62848K), 0.0241215 secs]<br/>如果不满意，可以进行调优，参数如文中上面参数所示，直接设置于JAVA_<br/> OTPS即可<br/><br/><span style="font-size: 12px;"><strong>3、利用JSTA查看GC情况</strong> </span><br/> <br/><br/>详细 附上<br/><br/><a href="http://zhumeng8337797.blog.163.com/blog/static/100768914201282833448384/" target="_blank">JConsole 远程监控Tomcat服务</a><br/><br/><a href="http://lanmaohome.blog.sohu.com/194483748.html" target="_blank">TOMCAT参数详解</a><br/><br/><a href="http://blog.csdn.net/fh13760184/article/details/6826505" target="_blank">jstat 使用</a><br/>其他工具<br/><br/><br/>JProfiler ：商业软件，需要付费。功能强大。详细说明参考<br/><br/>VisualVM ：JDK自带，功能强大，与JProfiler类似，官网地址下载http://visualvm.java.net/download.html(当然JDK7现在都自带了，在jdk1.7.0_10&#92;bin里)<br/><br/>JConsole和VisualVM 在JDK都自带了 o(∩_∩)o 哈哈&nbsp;&nbsp;感觉JProfiler这些收费的挺尴尬<br/><br/>OK，垃圾回收和调优原理打完收工，大概清楚 ，调优了就有方向了，具体参数可以查文档等<br/><br/>本文是基于HotSpot VM，其它JVM可能有些不一样。<br/>Tags - <a href="https://www.heckjj.com/tags/jvm/" rel="tag">jvm</a> , <a href="https://www.heckjj.com/tags/jdk/" rel="tag">jdk</a> , <a href="https://www.heckjj.com/tags/source/" rel="tag">source</a> , <a href="https://www.heckjj.com/tags/analyse/" rel="tag">analyse</a>
]]>
</description>
</item><item>
<link>https://www.heckjj.com/post//#blogcomment</link>
<title><![CDATA[[评论] JVM的内存模型、（GC）垃圾处理、调优监控(基于HotSpot VM，JDK1.5+)]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://www.heckjj.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>