2016年10月份遇到过一次oom,那时时是内存溢出问题,已解决。2017年3月份,4月份有各遇到一次oom故障,需要汇总下这方面知识了。 这里可能有很多都是copy别人的,总结自己和汇总别人的方方面面,以备查用。
涉及知识点:
jps,jstack以及线程各个状态介绍 ,top,jstat,jmap,mat以及插件,内存泄漏,内存溢出,gc,heap,young,
old区,jvm参数
jps -v
top -h -pPid
jstack -l pid >file
jstat -gcutil pid
jmap -histo[:live] pid
jmap -heap pid
jmap -dump:format=b,file=fileName pid
一:jps
jps是jdk提供的一个查看当前Java进程的小工具 jps -v
-v:输出jvm参数 jps -v | grep invite :
输出启动的invite关键词的服务的进程号和相关参数。
二:jstack
查看占用cpu过高的有问题代码==》定位出程序中的性能问题 jstack 查看线程 得知当前线程的运行
1.通过top命令查看当前CPU情况—- 》占用CPU过高,下面来排查是什么线程的什么代码导致CPU过高
- top -H -p155121 -H 指显示线程,-p 是指定进程 —》 得到CPU占用较高的线程,记下pid
从十进制转成十六进制表示 155166–>25e1e
通过jstack命令获取当前线程栈 jstack -l pid(进程pid) jstack -l 155121 > jstack.txt 查找nid=0x25e1e的线程栈
这里会显示对应的代码不合理之处。 然后到对应的代码中可查看不合理的逻辑。
该方法定位出程序中的性能问题 jstack Dump 日志文件中的线程状态 dump 文件里,值得关注的线程状态有:
1. 死锁,Deadlock(重点关注)
2. 执行中,Runnable
3. 等待资源,Waiting on condition(重点关注)
4. 等待获取监视器,Waiting on monitor entry(重点关注)
5. 暂停,Suspended
6. 对象等待中,Object.wait() 或 TIMED_WAITING
7. 阻塞,Blocked(重点关注)
8. 停止,Parked
9. 具体线程状态分析:http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html
补充:vim打开后 用 / 找到了一个词,那么 n N 就分别是向后,向前再找这个词。
三:jstat
jstat命令查看jvm的GC情况 性能分析
jstat -gcutil 167367 2000
会每2000秒一次显示进程号为167367 的java进成的GC情况
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
在线上的应用中通过会指定CMSInitiatingOccupancyFraction这个参数来指定当老年代使用了百分之多少的时候,通过CMS进行FGC,当然这个参数需要和这些参数一起使用“-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly”,CMSInitiatingOccupancyFraction的默认值是68,现在中文站线上的应用都是70,也就是说当老年代使用率真达到或者超过70%时,就会进行FGC。
四:jmap
jmap:得到运行java程序的内存分配的详细情况
jmap -heap 16737 : 167367进程id
- jmap -heap pid
- 查看java 堆(heap)使用情况
using thread-local object allocation.
Parallel GC with 4 thread(s) //GC 方式 Heap Configuration: //堆内存初始化配置
MinHeapFreeRatio=40 //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
MaxHeapFreeRatio=70 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
MaxHeapSize=512.0MB //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize = 1.0MB //对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
MaxNewSize =4095MB //对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
OldSize = 4.0MB //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
NewRatio = 8 //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
SurvivorRatio = 8 //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
8=2survivor/Eden ==> surviver/Eden = 4
PermSize= 16.0MB //对应jvm启动参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小
MaxPermSize=64.0MB //对应jvm启动参数-XX:MaxPermSize= :设置JVM堆的‘永生代’的最大大小
Heap Usage: //堆内存分步
PS Young Generation
Eden Space: //Eden区内存分布
capacity = 20381696 (19.4375MB) //Eden区总容量
used = 20370032 (19.426376342773438MB) //Eden区已使用
free = 11664 (0.0111236572265625MB) //Eden区剩余容量
99.94277218147106% used //Eden区使用比率
From Space: //其中一个Survivor区的内存分布
capacity = 8519680 (8.125MB)
used = 32768 (0.03125MB)
free = 8486912 (8.09375MB)
0.38461538461538464% used
To Space: //另一个Survivor区的内存分布
capacity = 9306112 (8.875MB)
used = 0 (0.0MB)
free = 9306112 (8.875MB)
0.0% used
PS Old Generation //当前的Old区内存分布
capacity = 366280704 (349.3125MB)
used = 322179848 (307.25464630126953MB)
free = 44100856 (42.05785369873047MB)
87.95982001825573% used
PS Perm Generation //当前的 “永生代” 内存分布
capacity = 32243712 (30.75MB)
used = 28918584 (27.57891082763672MB)
free = 3325128 (3.1710891723632812MB)
89.68751488662348% used
查看内存泄漏方式1:
-histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。num表示排列的序号。
-histo:live 167367 :同上,但是只打印存活对象的情况。
根据上述命令可分析出是否存在内存泄漏情况。
jmap -histo 167367 | head -n 10 |
#instance 是对象的实例个数
#bytes 是总占用的字节数
class name 对应的就是 Class 文件里的 class 的标识
B 代表 byte
C 代表 char
D 代表 double
F 代表 float
I 代表 int
J 代表 long
Z 代表 boolean
前边有 [ 代表数组, [I 就相当于 int[]
对象用 [L+ 类名表示
输出中[C对象占用Heap这么多,往往跟String有关,String其内部使用final char[]数组来保存数据的。
constMethodKlass/ methodKlass/ constantPoolKlass/ 与Classloader相关,常驻与Perm区。 看出目前堆内存中自己程序中的对象实例以及占用bytes,从而确定程序中哪些位置对这些对象进行创建使用且未被释放(典型的情况是将对象存入List等集合类而未被remove)。 也通过多次执行jmap -histo:live pid >mem.txt将每次结果定向到不同的txt中,然后对象对比。发现对象实例的增长与占用字节的变化。
查看内存泄漏方式2:
jmap -dump:format=b,file=mem.dat pid #将内存使用的详细情况输出到mem.dat 文件
通过jhat -port 7000 mem.dat可以将mem.dat的内容以web的方式暴露到网络,访问http://ip-server:7000查看。
把内存结构全部dump到二进制文件中,用eclipse的MemoryAnalyzer都可以分析内存结构。
可用此eclipse分析内存泄漏.
优化1: 1)首先配置JVM启动参数,让JVM在遇到OutOfMemoryError时自动生成Dump文件 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path
然后使用MAT分析工具,如jhat命令,eclipse的mat插件。
最后在eclipse中安装MAT插件(http://www.eclipse.org/mat/),然后在eclipse中,file---->open,
打开这个文件heap.bin,利用现成的OOM工具进行分析
用jhat命令可以参看 jhat -port 5000 heapDump 在浏览器中访问:http://localhost:5000/ 查看详细信息
这个时候将dump出的文件在ECLIPSE中打开,使用MAT进行分析(ECLIPSE需要先安装MAT插件)
总结:
总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
4.使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap -dump:format=b,file=
五:mat以及插件
.MAT插件安装: eclipse插件安装很简单,点击help ---install new software------add
然后添加新地址,路径为:http://download.eclipse.org/mat/1.6/update-site/
装完成之后,为了更有效率的使用
MAT,我们还需要做一些配置工作。因为通常而言,分析一个堆转储文件需要消耗很多的堆空间,
为了保证分析的效率和性能,在有条件的情况下,我们会建议分配给 MAT 尽可能多的内存资源:
编辑文件 MemoryAnalyzer.ini,在里面添加类似信息 -vmargs – Xmx4g。
open eclipse-> open-> file->
具体分析见: http://tivan.iteye.com/blog/1487855
六: top
top看到us,sy占比:
cpu的占有线程类型总的来说分为两种:
us :用户空间占用CPU百分比
sy :内核空间占用CPU百分比
在linux下可以通过top命令查看详细,示例如下:
一般来讲CPU us高的解决方法:
CPU us 高的原因主要是执行线程不需要任何挂起动作,且一直执行,
导致CPU 没有机会去调度执行其他的线程。
CPU sy高的解决方法:
CPU sy 高的原因主要是线程的运行状态要经常切换,对于这种情况,
常见的一种优化方法是减少线程数。
系统优化
如果找出了哪些功能点占用cpu高,接下来就需要优化了,可以从业务和技术手段两方面来进行,
平时工作中比较常用的技术手段:
弹性时间:对高使用率的请求,分散到不同的时间,比如采用队列或异步,减少同一时间处理的请求。
批处理或定时任务:把请求组合成批,这样可以使得时间真真的都有效的用在了处理,
而不是网络传输等准备工作上。(减少网络传输、数据库连接、socket连接)
缓存:将结果缓存起来,空间换时间。
如果是gc线程比较费时,则需要进一步的定位:
首先查看一下gc策略是否合理,然后用命令jmap -F -dump:live,file=jmap.hprof [PID]
导出内存dump文件。用Eclipse Memory Analyzer(
MAT)分析导出来的文件,分析是哪个类占用内存比较多,分析出可能存在内存泄露的地方。
注意jvm分配内存时一个大对象的分配比多个小对象的分配效率要低,如果对象比较大
,进行拆分能提高效率,具体原因如下:
Java对象所占用的内存主要从堆上进行分配,堆是所有线程共享的,因此在堆上分配内存
时需要进行加锁,这导致了创建对象开销比较大。当堆上空间不足时,会触发GC,如果
GC后空间仍然不足,则抛出OutOfMemory错误信息。Sun JDK为了提升内存分配的效率,会为每个新创建的线程在新生代的Eden
Space上分配一块独立的空间,这块空间称为TLAB(Thread Local Allocation
Buffer),其大小由JVM根据运行情况计算而得,可通过-XX:TLABWasteTargetPercent来
设置TLAB可占用的Eden Space的百分比,默认值为1%。JVM将根据这个比率、线程数量及
线程是否频繁分配对象来给每个线程分配合适大小的TLAB空间
。在TLAB上分配内存时不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上
分配,如果对象过大或TLAB空间已用完,则仍然在堆上进行分配,因此在编写Java程序时,
通常多个小的对象比大的对象分配起来更加高效。
七:jvm参数
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4
-XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM初始内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 +
持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对
系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈
大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成
更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在 3000~5000 左右。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,
则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个
Survivor区与一个 Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过
Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为
一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活
时间,增加在年轻代即被回收的概论。
-XX:+UseParallelGC -XX:ParallelGCThreads=20
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,
年轻代使用并发收集,而年老代仍旧使用串行收集。
XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收
。此值最好配置与处理器数目相等。
-XX:+UseParallelOldGC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集
-XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的
配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。
-XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系
统配置自行设置,所以无需再设置此值。
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片
常见JVM参数配置汇总
堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代
占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。
如:3,表示 Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行
收集线程数
较小堆引起的碎片问题
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他
会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间
以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使
用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下JVM参数配置:
-XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对
年老代进行压缩
1: heap size
a: -Xmx<n>
指定 jvm 的最大 heap 大小 , 如 :-Xmx=2g
b: -Xms<n>
指定 jvm 的最小 heap 大小 , 如 :-Xms=2g , 高并发应用, 建议和-Xmx一样, 防止因为内存收缩/突然增大带来的性能影响。
c: -Xmn<n>
指定 jvm 中 New Generation 的大小 , 如 :-Xmn256m。 这个参数很影响性能, 如果你的
程序需要比较多的临时内存, 建议设置到512M, 如果用的少, 尽量降低这个数值, 一般
来说128/256足以使用了。
d: -XX:PermSize=<n>
指定 jvm 中 Perm Generation 的最小值 , 如 :-XX:PermSize=32m。 这个参数需要看你
的实际情况,。 可以通过jmap 命令看看到底需要多少。
e: -XX:MaxPermSize=<n>
指定 Perm Generation 的最大值 , 如 :-XX:MaxPermSize=64m
f: -Xss<n>
指定线程桟大小 , 如 :-Xss128k, 一般来说,webx框架下的应用需要256K。 如果你
的程序有大规模的递归行为, 请考虑设置到512K/1M。 这个需要全面的测试才能知道。
不过, 256K已经很大了。 这个参数对性能的影响比较大的。
g: -XX:NewRatio=<n>
指定 jvm 中 Old Generation heap size 与 New Generation 的比例 , 在使用 CMS GC
的情况下此参数失效 , 如 :-XX:NewRatio=2
h: -XX:SurvivorRatio=<n>
指定 New Generation 中 Eden Space 与一个 Survivor Space 的 heap size 比例 ,
-XX:SurvivorRatio=8, 那么在总共 New Generation 为 10m 的情况下 ,Eden Space 为 8m
i: -XX:MinHeapFreeRatio=<n>
指定 jvm heap 在使用率小于 n 的情况下 ,heap 进行收缩 ,Xmx==Xms 的情况下无效 ,
如 :-XX:MinHeapFreeRatio=30
j: -XX:MaxHeapFreeRatio=<n>
指定 jvm heap 在使用率大于 n 的情况下 ,heap 进行扩张 ,Xmx==Xms 的情况下无效 ,
如 :-XX:MaxHeapFreeRatio=70
k: -XX:LargePageSizeInBytes=<n>
指定 Java heap 的分页页面大小 , 如 :-XX:LargePageSizeInBytes=128m
2: garbage collector
a: -XX:+UseParallelGC
指定在 New Generation 使用 parallel collector, 并行收集 , 暂停 app threads,
同时启动多个垃圾回收 thread, 不能和 CMS gc 一起使用 . 系统吨吐量优先 , 但是会
有较长长时间的 app pause, 后台系统任务可以使用此 gc
b: -XX:ParallelGCThreads=<n>
指定 parallel collection 时启动的 thread 个数 , 默认是物理 processor 的个数 ,
c: -XX:+UseParallelOldGC
指定在 Old Generation 使用 parallel collector
d: -XX:+UseParNewGC
指定在 New Generation 使用 parallel collector, 是 UseParallelGC 的 gc 的升级版本 ,
有更好的性能或者优点 , 可以和 CMS gc 一起使用
e: -XX:+CMSParallelRemarkEnabled
在使用 UseParNewGC 的情况下 , 尽量减少 mark 的时间
f: -XX:+UseConcMarkSweepGC
指定在 Old Generation 使用 concurrent cmark sweep gc,gc thread 和 app thread 并行
( 在 init-mark 和 remark 时 pause app thread). app pause 时间较短 , 适合交互性强的系统 , 如 web server
g: -XX:+UseCMSCompactAtFullCollection
在使用 concurrent gc 的情况下 , 防止 memory fragmention, 对 live object 进行整理 ,
使 memory 碎片减少
h: -XX:CMSInitiatingOccupancyFraction=<n>
指示在 old generation 在使用了 n% 的比例后 , 启动 concurrent collector,
默认值是 68, 如 :-XX:CMSInitiatingOccupancyFraction=70
有个 bug, 在低版本(1.5.09 and early)的 jvm 上出现 , http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6486089
i: -XX:+UseCMSInitiatingOccupancyOnly
指示只有在 old generation 在使用了初始化的比例后 concurrent collector 启动收集
3:others
a: -XX:MaxTenuringThreshold=<n>
指定一个 object 在经历了 n 次 young gc 后转移到 old generation 区 , 在 linux64 的
java6 下默认值是 15, 此参数对于 throughput collector 无效 , 如 :-XX:MaxTenuringThreshold=31
b: -XX:+DisableExplicitGC
禁止 java 程序中的 full gc, 如 System.gc() 的调用. 最好加上么, 防止程序在代码里误用了
。对性能造成冲击。
c: -XX:+UseFastAccessorMethods
get,set 方法转成本地代码
d: -XX:+PrintGCDetails
打应垃圾收集的情况如 :
[GC 15610.466: [ParNew: 229689K->20221K(235968K), 0.0194460 secs]
1159829K->953935K(2070976K), 0.0196420 secs]
e: -XX:+PrintGCTimeStamps
打应垃圾收集的时间情况 , 如 :
[Times: user=0.09 sys=0.00, real=0.02 secs]
f: -XX:+PrintGCApplicationStoppedTime
打应垃圾收集时 , 系统的停顿时间 , 如 :
Total time for which application threads were stopped: 0.0225920 seconds
4: a web server product sample and process
JAVA_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
最初的时候我们用 UseParallelGC 和 UseParallelOldGC,heap 开了 3G,NewRatio 设成 1. 这样的
配置下 young gc 发生频率约 12,3 妙一次 , 平均每次花费 80ms 左右 ,full gc 发生的频率极低 ,
每次消耗 1s 左右 . 从所有 gc 消耗系统时间看 , 系统使用率还是满高的 , 但是不论是 young gc
还是 old gc,applicaton thread pause 的时间比较长 , 不合适 web 应用 . 我们也调小
New Generation 的 , 但是这样会使 full gc 时间加长 .
后来我们就用 CMS gc(-XX:+UseConcMarkSweepGC), 当时的总 heap 还是 3g, 新生代 1.5g 后 ,
观察不是很理想 , 改为 jvm heap 为 2g 新生代设置 -Xmn1g, 在这样的情况下 young gc 发生的
频率变成 ,7,8 妙一次 , 平均每次时间 40~50 毫秒左右 ,CMS gc 很少发生 , 每次时间在 init-mark
和 remark(two steps stop all app thread) 总共平均花费 80~90ms 左右 .
在这里我们曾经 New Generation 调大到 1400m, 总共 2g 的 jvm heap, 平均每次 ygc 花费
时间 60~70ms 左右 ,CMS gc 的 init-mark 和 remark 之和平均在 50ms 左右 , 这里我们意识
到错误的方向 , 或者说 CMS 的作用 , 所以进行了修改
最后我们调小 New Generation 为 256m,young gc 2,3 秒发生一次 , 平均停顿时间在 25 毫秒左右 ,
CMS gc 的 init-mark 和 remark 之和平均在 50ms 左右 , 这样使系统比较平滑 , 经压力测试 ,
这个配置下系统性能是比较高的
在使用 CMS gc 的时候他有两种触发 gc 的方式 :gc 估算触发和 heap 占用触发 .
我们的 1.5.0.09 环境下有次 old 区 heap 占用再 30% 左右 , 她就频繁 gc,
个人感觉系统估算触发这种方式不靠谱 , 还是用 heap 使用比率触发比较稳妥 .
这些数据都来自 64 位测试机 , 过程中的数据都是我在 jboss log 找的 ,
当时没有记下来 , 可能存在一点点偏差 , 但不会很大 , 基本过程就是这样 .
5: 总结
web server 作为交互性要求较高的应用 , 我们应该使用 Parallel+CMS,UseParNewGC 这个在 jdk6 -server 上是默认的 ,new generation gc, 新生代不能太大 , 这样每次 pause 会短一些 .CMS mark-sweep generation 可以大一些 , 可以根据 pause time 实际情况控制。
七:补充
1、内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案; 内存泄漏的原因分析
总结出来只有一条: 存在无效的引用! 良好的模块设计以及合理使用设计模式有助于解决此问题。 2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。