POI导出excel的时候出现gcoverheadlimit
问题现象
项⽬中需要⼀个数据导出excel功能,因为导出的⽂件需要是正式excel格式,包含多个sheet页,采⽤csv等⽅式⽆法满⾜需求,所以采⽤poi⽅式。考虑到poi⽅式会占⽤较多的内存,所以限制每次最多可以导出10000条数据,并且在开发环境⾃测的时候⽤可允许的最⼤的数据进⾏测试正常,通过jvisualvm观察内存使⽤情况发现old区内的最多的时候占⽤到200M左右,属于需求可接受范围。但是在测试环境测试的时候同样的数据会报异常,异常如下:
2011-01-05 10:32:03,783 [] WARN support.DefaultExceptionMonitor - Unexpected exception.
java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.wKeyIterator(HashMap.java:840)
at java.util.HashMap$KeySet.iterator(HashMap.java:874)
at java.util.HashSet.iterator(HashSet.java:153)
at sun.nio.ch.SelectorImpl.processDeregisterQueue(SelectorImpl.java:127)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:69)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)
at sun.nio.ch.SelectorImpl.lect(SelectorImpl.java:80)
at org.ansport.socket.nio.SocketIoProcessor$Worker.run(SocketIoProcessor.java:480)
at org.apache.mina.util.NamePrervingRunnable.run(NamePrervingRunnable.java:51)
at urrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at urrent.ThreadPoolExecutor$Worker.run(ThreadPoolExec中国国有企业
utor.java:908)
at java.lang.Thread.run(Thread.java:619)
GC overhead limit:This message means that for some reason the garbage collector is taking an excessive amount of time (by default 98% of all CPU time of the process) and recovers very little memory in each run (by default 2% of the heap).
即意味着CPU的⼤多数时间在执⾏GC,但是GC回收到的内存很少。也就是程序不再去执⾏其他的⼯作⽽⼀直在进⾏GC。
问题原因调查
程序结构:
getDataList(); 注:取得10000条数据
generateWorkBook(); 注:构建excelbook
write(); 注:调⽤workBook的write⽅法,将excel写⼊输出流中
1. 调试发现,是进⾏write()的时候报出异常。初步定位:有可能poi中的write⽅法有问题,但是这不能解释为什么开发环境不会出现这个问题
2. 查看程序执⾏过程中的GC情况
(1). jps -v:打印出当前java进程的相信信息,找到需要的pid
(2). jstat -gc pid 500:每隔0.5秒,打印GC情况
得到GC情况如下(节选),可见其实在⽣成workbook的时候已经把内存都占⽤了,在后续的时候⼀直在疯狂的执⾏fullGC,但是确没有办法回收掉内存,导致报异常
0C &nbs美女写真图
p; S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
<!-----------------------------查询数据 start----------------------------------------->
29312.0 30784.0 0.0 12495.0 111296.0 81878.4 157248.0 107377.5 131072.0 58695.9 17 0.259 2 0.256 0.515
29312.0 29632.0 17012.5 0.0 114240.0 0.0 157248.0 107377.5 131072.0 61570.7 18 0.281 2 0.256 0.537
29312.0 29632.0 17012.5 0.0 114240.0 113694.2 157248.0 107377.5 131072.0 62525.5 18 0.281 2 0.256 0.537
30848.0 29632.0 0.0 29602.5 114240.0 17769.8 157248.0 117265.5 131072.0 62525.5 19 0.309 2 0.256 0.565
30848.0 29632.0 0.0 29602.5 114240.0 82492.0 157248.0 117265.5 131072.0 66869.2 19 0.309 2 0.256 0.565
30848.0 40640.0 27969.2 0.0 93440.0 2684.5 157248.0 129150.4 131072.0 69366.5 20 0.335 2 0.256 0.591
30848.0 40640.0 27969.2 0.0 93440.0 33808.0 157248.0 129150.4 131072.0 69492.5&n婴儿坐飞机
bsp; 20 0.335 2 0.256 0.591
30848.0 40640.0 27969.2 0.0 93440.0 88751.4 157248.0 129150.4 131072.0 69538.6 21 0.335 2 0.256 0.591
40640.0 40640.0 0.0 0.0 93440.0 25459.3 250368.0 157248.0 131072.0 69576.3 21 0.359 3 0.687 1.046
40640.0 55360.0 39744.0 0.0 64000.0 38072.3 250368.0 157248.0 131072.0 69599.2 22 0.389 3 0.687 1.076
<!------------------------------查询数据end------------------------------------------->
<!-----------------------------⽣成workBook start------------------------------------->
58240.0 58240.0 0.0 14400.0 58240.0 0.0 250368.0 229032.0 131072.0 69647.0 25 0.466 4 0.687 1.153
56512.0 58240.0 42912.0 0.0 58240.0 2304.1 349568.0 红杉资本创始人
; 238586.7 131072.0 69504.9 28 0.508 4 1.305 1.812
55360.0生活日记300字
56960.0 0.0 14336.0 58240.0 0.0 349568.0 310706.7 131072.0 69504.9 31 0.588 5 1.305 1.893
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 324956.3 131072.0 69504.9 31 0.588 6 1.980 2.568
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 339142.1 131072.0 69801.6 31 0.588 7 2.751 3.339
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 349567.9 131072.0 69828.7 31 0.588 8 3.540 4.128
55360.0 56960.0 0.0 0.0 58240.0 44166.5 349568.0 349568.0 131072.0 69821.5 31 0.588 9 4.425 5.014
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 349568.0 131072.0 69821.6 31 0.588 10 5.293 5.881
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 349568.0 131072.0 69821.6 31 0.588 11 6.184 6.772
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 349568.0 131072.0 69821.6 31 0.588 12 7.038 7.626
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 349568.0 131072.0 69821.6 31 0.588 13 7.894 8.482
55360.0 56960.0 0.0 0.0 58240.0 58240.0 349568.0 349568.0 131072.0 69821.6 31 0.588 14 8.723 9.311
<!-----------------------------.................------------------------------------->
3. 貌似是内存真的不够⽤了!调整内存⼤⼩试下
注:开发环境和测试环境启动参数都是-Xms128m -Xmx512m,即内存使⽤最⼤512
把参数调整为-Xms1024m -Xmx1024m后执⾏程序,导出正常。确实是内存不够⽤了,不过还是不能解释开发环境和测试环境结果不⼀
样的问题
4. 打印开发环境的GC情况,发现OU最⼤的时候也只是到200M之内
为什么同样的数据同样的程序在两个环境的使⽤的内存会不⼀样呢?
5. 在开发和测试环境执⾏导出时dump内存,查找原因
(1). jmap -dump:format=b,file=heap.bin <pid>:⽣成内存快照
(2). jhat -port 8888 heap.丙戊酸钠说明书
bin:通过jhat把内存快照⽣成⽹页⽂件,并开发端⼝8888
(3)七年级上册语文知识点
. 访问,查看快照信息(172.29.61.77:测试环境地址)
6. 确定两个环境有那些地⽅不同
(1). java版本:java -version
(2). jvm启动参数:jps -v
(3). 查看服务器信息:uname -a
发现测试环境是64位,开发环境是32位
通常64位JVM消耗的内存会⽐32位的⼤1.5倍,这是因为对象指针在64位架构下,长度会翻倍(更宽的寻址)
8. 验证是否是这个原因引起
测试环境jvm启动添加参数-XX:+UCompresdOops
添加参数后,再次执⾏导出程序,正常。观察GC情况,发现OU最⼤的时候在⼆百⼏⼗M,虽然还是⽐开发环境⽤的内存要⼤,不过⽐之前已经⼩了很多了。
结论
之所以在测试环境出现内存异常情况⽽在开发环境正常原因是64位jvm对内存的消耗要⽐32位的⼤出很多,可以通过UCompresdOops这个参数来进⾏指针的压缩,不过这个在节约内存的同时会增⼤jvm的负担,具体是否要为线上添加这个参数需要权衡。
查找问题过程中遇到的另⼀个问题
1. 现象
在点击⼀次"导出"按钮后,在eclip中进⾏调试,调试过程中会发现⼜有另⼀个同样的请求过来,即每个断点都会执⾏两次。
2. 分析
浏览器⾃动重新发?
⽤firebug观察发出的请求,只有⼀个,不是
其他⼈也在执⾏这个操作?
查看cookielog,仅有⼀条记录,不是
mod_jk⾃动转发
查看mod_jk的配置:
...
JkWorkerProperty worker.localnode.socket_keepalive=True
JkWorkerProperty worker.localnode.socket_timeout=20
...
socket_timeout:Socket timeout in conds ud for the communication channel between JK and remote host. If the remote host does not respond inside the timeout specified, JK will generate an error, and retry again. If t to zero (default) JK will wait for an infinite amount of time on all socket operations. 即如果转发请求后20秒没有接收到响应,就会返回给⽤户⼀个error,同时重新发起⼀次请求。
莫⾮是因为本来导出这⾥就很中毒了吃什么解毒
慢,加上调试的时间超过了预设的20秒,所以导致retry了?
3. 验证
将socket_timeout设为0,再次进⾏调试,果然那个神秘的请求没有再出现过!