1.输出该进程拥有的线程总数
ps -mp pid -o THREAD,tid,time | wc -l
2.输出占用cpu最大的前10线程
ps -mp pid -o THREAD,tid,time | sort -rn | head -10
3.查看进程中线程当前的的状态(thread dump)
jstack pid
对于查找blocked线程比较有意义
"resin-port-9040-24" #24 daemon prio=5 os_prio=31 tid=0x00007ffbfc212000 nid=0x8503 runnable [0x0000700011cbb000]java.lang.Thread.State: RUNNABLEat java.net.PlainSocketImpl.socketAccept(Native Method)at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)at java.net.ServerSocket.implAccept(ServerSocket.java:545)at java.net.ServerSocket.accept(ServerSocket.java:513)at com.caucho.vfs.QServerSocketWrapper.accept(QServerSocketWrapper.java:105)at com.caucho.network.listen.TcpPort.accept(TcpPort.java:1380)at com.caucho.network.listen.TcpSocketLink.accept(TcpSocketLink.java:1025)at com.caucho.network.listen.TcpSocketLink.handleAcceptTaskImpl(TcpSocketLink.java:975)at com.caucho.network.listen.ConnectionTask.runThread(ConnectionTask.java:117)at com.caucho.network.listen.ConnectionTask.run(ConnectionTask.java:93)at com.caucho.network.listen.SocketLinkThreadLauncher.handleTasks(SocketLinkThreadLauncher.java:169)at com.caucho.network.listen.TcpSocketAcceptThread.run(TcpSocketAcceptThread.java:61)at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)"resin-port-9040-launcher" #23 daemon prio=5 os_prio=31 tid=0x00007ffbfc211000 nid=0x8703 waiting on condition [0x0000700011c78000]java.lang.Thread.State: TIMED_WAITING (parking)at sun.misc.Unsafe.park(Native Method)at java.util.concurrent.locks.LockSupport.parkUntil(LockSupport.java:372)at com.caucho.env.thread2.AbstractTaskWorker2.run(AbstractTaskWorker2.java:270)at com.caucho.env.thread2.ResinThread2.runTasks(ResinThread2.java:173)at com.caucho.env.thread2.ResinThread2.run(ResinThread2.java:118)
更直观的统计:
jstack pid | grep 'java.lang.Thread.State' | sort -n|uniq -c| sort -nr
14 java.lang.Thread.State: RUNNABLE12 java.lang.Thread.State: TIMED_WAITING (parking)2 java.lang.Thread.State: WAITING (on object monitor)1 java.lang.Thread.State: TIMED_WAITING (on object monitor)
1.导出当前堆中存活的对象到文件中
jmap -dump:live,format=b,file=heap-dump.hprof
2.查看堆文件
jhat
也可以使用jdk自带的jvisualvm工具查看堆文件.
也可以使用IBM Heap Analyzer工具分析堆文件.IBM的HeapAnalyzer看到的更详细,对象的全部信息都能查看到.
1.查看内存当前各个区域占用的大小
jstat -gcutil pid
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT0.00 0.00 10.13 12.93 96.09 92.68 35 6.568 3 7.159 13.727
或者使用
jmap -heap pid
Heap Configuration:MinHeapFreeRatio = 40MaxHeapFreeRatio = 70MaxHeapSize = 2147483648 (2048.0MB)NewSize = 786432000 (750.0MB)MaxNewSize = 786432000 (750.0MB)OldSize = 1361051648 (1298.0MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 134217728 (128.0MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 134217728 (128.0MB)G1HeapRegionSize = 0 (0.0MB)Heap Usage:
New Generation (Eden + 1 Survivor Space):capacity = 707788800 (675.0MB)used = 414354616 (395.1593551635742MB)free = 293434184 (279.8406448364258MB)58.542126690899885% used
Eden Space:capacity = 629145600 (600.0MB)used = 352045688 (335.73693084716797MB)free = 277099912 (264.26306915283203MB)55.956155141194664% used
From Space:capacity = 78643200 (75.0MB)used = 62308928 (59.42242431640625MB)free = 16334272 (15.57757568359375MB)79.22989908854167% used
To Space:capacity = 78643200 (75.0MB)used = 0 (0.0MB)free = 78643200 (75.0MB)0.0% used
concurrent mark-sweep generation:capacity = 1361051648 (1298.0MB)used = 418792640 (399.39178466796875MB)free = 942259008 (898.6082153320312MB)30.76978310230884% used
2.查看内存gc的情况
jstat -gc pid
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
76800.0 76800.0 0.0 0.0 614400.0 53387.9 1329152.0 171834.9 82048.0 78841.9 8832.0 8185.6 35 6.568 3 7.159 13.727
3.当前存活的对象
jmap -histo:live pid
4.查看当前配置jvm配置信息
jinfo pid
3951: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.DecimalDV
3952: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.DoubleDV
3953: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.DurationDV
3954: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.EntityDV
3955: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.FloatDV
3956: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.HexBinaryDV
3957: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.IDDV
3958: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.IDREFDV
3959: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.IntegerDV
3960: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.ListDV
3961: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.MonthDV
3962: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.MonthDayDV
3963: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.PrecisionDecimalDV
3964: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.StringDV
3965: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.TimeDV
3966: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.UnionDV
3967: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl$1
3968: 1 16 com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl$4
jvm参数说明:
cms收集器的配置
-XX:+UseCMSInitiatingOccupancyOnly JVM不基于运行时收集的数据来启动CMS垃圾收集周期。而是,当该标志被开启时,JVM通过CMSInitiatingOccupancyFraction 的值进行每一次CMS收集,而不仅仅是第一次。然而,请记住大多数情况下,JVM比我们自己能作出更好的垃圾收集决策。因此,只有当我们充足的理由(比如测试)并且对应用程序产生的对象的生命周期有深刻的认知时,才应该使用该标志。
-XX:+ExplicitGCInvokesConcurrent and
-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
如今,被广泛接受的最佳实践是避免显式地调用GC(所谓的“系统GC”),即在应用程序中调用system.gc()。然而,这个建议是不管使用的GC算法的,值得一提的是,当使用CMS收集器时,系统GC将是一件很不幸的事,因为它默认会触发一次Full GC。幸运的是,有一种方式可以改变默认设置。标志-XX:+ExplicitGCInvokesConcurrent命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC。第二个标志-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses保证当有系统GC调用时,永久代也被包括进CMS垃圾回收的范围内。因此,通过使用这些标志,我们可以防止出现意料之外的”stop-the-world”的系统GC。
-XX:+ParallelRefProcEnabled 如果应用有大量的引用或者finalizable对象需要处理,指定下面这个选项可以减少垃圾回收的时间:
他会是用多个的引用处理线程,而不是单个线程。这个选项不会启用多线程运行方法的finalizer。他会使用很多线程去发现需要排队通知的finalizable对象。
-XX:+UseParNewGC ParNew收集器器是许多运⾏行行在Server模式下的虚拟机中⾸首选的新⽣生代收集器器。除去性能因素,很重要的原因是 除了了Serial收集器器外,⽬目前只有它能与CMS收集器器配合⼯工作。
吞吐量收集器
-XX:+UseSerialGC 我们使用该标志来激活串行垃圾收集器,例如单线程面向吞吐量垃圾收集器。 无论年轻代还是年老代都将只有一个线程执行垃圾收集。 该标志被推荐用于只有单个可用处理器核心的JVM。 在这种情况下,使用多个垃圾收集线程甚至会适得其反,因为这些线程将争用CPU资源,造成同步开销,却从未真正并行运行。
-XX:+UseParallelGC 有了这个标志,我们告诉JVM使用多线程并行执行年轻代垃圾收集。 在我看来,Java 6中不应该使用该标志因为-XX:+UseParallelOldGC显然更合适。 需要注意的是Java 7中该情况改变了一点(详见本概述),就是-XX:+UseParallelGC能达到-XX:+UseParallelOldGC一样的效果。
-XX:+UseParallelOldGC 该标志的命名有点不巧,因为”老”听起来像”过时”。 然而,”老”实际上是指年老代,这也解释了为什么-XX:+UseParallelOldGC要优于-XX:+UseParallelGC:除了激活年轻代并行垃圾收集,也激活了年老代并行垃圾收集。 当期望高吞吐量,并且JVM有两个或更多可用处理器核心时,我建议使用该标志。
作为旁注,HotSpot的并行面向吞吐量垃圾收集算法通常称为”吞吐量收集器”,因为它们旨在通过并行执行来提高吞吐量。
-XX:ParallelGCThreads 通过-XX:ParallelGCThreads&#61;我们可以指定并行垃圾收集的线程数量。 例如&#xff0c;-XX:ParallelGCThreads&#61;6表示每次并行垃圾收集将有6个线程执行。 如果不明确设置该标志&#xff0c;虚拟机将使用基于可用(虚拟)处理器数量计算的默认值。 决定因素是由Java Runtime。availableProcessors()方法的返回值N&#xff0c;如果N<&#61;8&#xff0c;并行垃圾收集器将使用N个垃圾收集线程&#xff0c;如果N>8个可用处理器&#xff0c;垃圾收集线程数量应为3&#43;5N/8。
当JVM独占地使用系统和处理器时使用默认设置更有意义。 但是&#xff0c;如果有多个JVM(或其他耗CPU的系统)在同一台机器上运行&#xff0c;我们应该使用-XX:ParallelGCThreads来减少垃圾收集线程数到一个适当的值。 例如&#xff0c;如果4个以服务器方式运行的JVM同时跑在在一个具有16核处理器的机器上&#xff0c;设置-XX:ParallelGCThreads&#61;4是明智的&#xff0c;它能使不同JVM的垃圾收集器不会相互干扰。
-XX:-UseAdaptiveSizePolicy 吞吐量垃圾收集器提供了一个有趣的(但常见&#xff0c;至少在现代JVM上)机制以提高垃圾收集配置的用户友好性。 这种机制被看做是HotSpot在Java 5中引入的”人体工程学”概念的一部分。 通过人体工程学&#xff0c;垃圾收集器能将堆大小动态变动像GC设置一样应用到不同的堆区域&#xff0c;只要有证据表明这些变动将能提高GC性能。 “提高GC性能”的确切含义可以由用户通过-XX:GCTimeRatio和-XX:MaxGCPauseMillis(见下文)标记来指定。
重要的是要知道人体工程学是默认激活的。 这很好&#xff0c;因为自适应行为是JVM最大优势之一。 不过&#xff0c;有时我们需要非常清楚对于特定应用什么样的设置是最合适的&#xff0c;在这些情况下&#xff0c;我们可能不希望JVM混乱我们的设置。 每当我们发现处于这种情况时&#xff0c;我们可以考虑通过-XX:-UseAdaptiveSizePolicy停用一些人体工程学。
-XX:GCTimeRatio 通过-XX:GCTimeRatio&#61;我们告诉JVM吞吐量要达到的目标值。 更准确地说&#xff0c;-XX:GCTimeRatio&#61;N指定目标应用程序线程的执行时间(与总的程序执行时间)达到N/(N&#43;1)的目标比值。 例如&#xff0c;通过-XX:GCTimeRatio&#61;9我们要求应用程序线程在整个执行时间中至少9/10是活动的(因此&#xff0c;GC线程占用其余1/10)。 基于运行时的测量&#xff0c;JVM将会尝试修改堆和GC设置以期达到目标吞吐量。 -XX:GCTimeRatio的默认值是99&#xff0c;也就是说&#xff0c;应用程序线程应该运行至少99%的总执行时间。
-XX:MaxGCPauseMillis 通过-XX:GCTimeRatio&#61;告诉JVM最大暂停时间的目标值(以毫秒为单位)。 在运行时&#xff0c;吞吐量收集器计算在暂停期间观察到的统计数据(加权平均和标准偏差)。 如果统计表明正在经历的暂停其时间存在超过目标值的风险时&#xff0c;JVM会修改堆和GC设置以降低它们。 需要注意的是&#xff0c;年轻代和年老代垃圾收集的统计数据是分开计算的&#xff0c;还要注意&#xff0c;默认情况下&#xff0c;最大暂停时间没有被设置。
如果最大暂停时间和最小吞吐量同时设置了目标值&#xff0c;实现最大暂停时间目标具有更高的优先级。 当然&#xff0c;无法保证JVM将一定能达到任一目标&#xff0c;即使它会努力去做。 最后&#xff0c;一切都取决于手头应用程序的行为。
OutofMemory&#xff08;OOM&#xff09;相关的选项
如果程序发生了OOM后&#xff0c;JVM可以配置一些选项来做些善后工作&#xff0c;比如把内存给dump下来&#xff0c;或者自动采取一些别的动作。
$ java -XX:&#43;HeapDumpOnOutOfMemoryError -XX:HeapDumpPath&#61;/tmp/heapdump.hprof -XX:OnOutOfMemoryError &#61;"sh ~/start.sh" myserver
开启远程jmx监控,这是个组合,一起用就行了.开启了远程jmx监控后,就可以在本地启动jconsole,等一些内存分析工具对服务器内存进行分析了.一般测试环境用,正式环境慎用.
-server //开启服务模式
-Xmn750M //年轻代配置xmx的3/8
-Xmx2048M //堆的最大值
-Xms2048M //堆的最小值
-XX:MetaspaceSize&#61;128m //元数据区
-XX:MaxMetaspaceSize&#61;128m
-Xss256k //一个线程占用的栈大小
-XX:SurvivorRatio&#61;8
-XX:&#43;UseConcMarkSweepGC //激活cms收集器
-XX:MaxTenuringThreshold&#61;8 //最大gc次数后进入老年代.默认15
-XX:ParallelGCThreads&#61;24 //cms收集时,开启多少线程
-XX:&#43;ParallelRefProcEnabled //finalizable多线程回收
-XX:&#43;UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction&#61;75 //老年代超过75%,开始cms回收
-XX:&#43;ExplicitGCInvokesConcurrent //JVM无论什么时候调用系统GC&#xff0c;都执行CMS GC
-verbose:gc -XX:&#43;PrintGCDetails -XX:&#43;PrintGCTimeStamps -XX:&#43;PrintGCDateStamps -XX:&#43;PrintFlagsFinal -XX:&#43;UseParNewGC //多线程新生代收集器-Xloggc:/logs/gc.log
解说:由于系统对吞吐量要求不高,所以主要是对响应方面的内存优化,防止频繁FULL GC和频繁gc.
上面文章也是大量参考网友的,自己再重新整合,修改,添加了一些东西.但是忘记记录地址了,这里说声对比起,如有发现原文抄袭的情况,请联系我,我贴上转载地址.