Java程序持续Full GC的处理经历

简介:

 1. 发现问题

    最近在检查爬虫程序运行情况的时候发现采集速度非常慢,查看cpu占用率的时候发现有一个内核一直是100%,按理说多线程的程序不应该会出现这样的情况。第一反应就是用jstack -l [pid]把线程dump出来查看栈情况,但没发现什么异常。然后就考虑用jmap -heap [pid]把内存使用情况打印出来看看,奇怪的是出现好几次连接不上的情况,等打印出来发现居然旧生代已经满了。把内存调大,发现过不了一会又是这样,确实非常蹊跷。

2. 深入调查

    看来问题比较棘手,只好用更细致的方式去分析了。一方面打开了GC日志,同时在运行时用jstat -gcutil [pid] 1000来跟踪GC情况。现象很奇怪,旧生代空间缓慢增长,但突然新生代内存占用100%,旧生代紧接着也变成100%,然后就一直处于full gc,但内存丝毫没有减少,整个过程持续了5分钟。(截图忘记保存了,悲剧...)

    看现象就是对象爆炸,但程序已经运行很久了,如果有这么严重的bug应该早就发现了。严谨起见,我用jmap -histo [pid]把程序的对象情况打印出来,结果非常惊讶。

 
  1. num     #instances         #bytes  class name 
  2. --------------------------------------------- 
  3.   1:      30110820     1204432800  org.jsoup.parser.ParseError 
  4.   2:         33076      156025088  [Ljava.lang.Object; 
  5.   3:         68836       98796360  [C 

    系统中居然出现那么多ParserError对象,这个是程序中用到的一个Jsoup开源包里面的东西。看命名像是一个Exception,但查看源码时才发现居然是一个Class。至于这个东西从哪里蹦出来的呢?!我在现象出现的时候打印了下线程栈信息,果然定位到了生成这个对象的那个位置。

    在源码中找到相应的实现,主要是调用了这样一个方法:

 
  1. private boolean trackErrors = true;
  2. ......
  3. void error(TokeniserState state) { 
  4.     if (trackErrors) 
  5.         errors.add(new ParseError("Unexpected character in input", reader.current(), state, reader.pos())); 

    这里有一个trackErrors做开关,默认是true,但找了一下,居然没有最外层的方法去控制它,而errors这个对象也是一个private值,没有任何调用,可能是作者自己测试用的。

3. 问题的处理

    原因调查清楚,处理就很简单了。直接把源码中trackErrors的默认值改成false,再确认了一下其他相关调用的方法,然后重新编译打包,把原始包替换了。

4. 总结

    找问题还是要先分析出可能的原因,然后借用工具去定位问题,很多时候数据比经验更可靠。



本文转自passover 51CTO博客,原文链接:http://blog.51cto.com/passover/715294,如需转载请自行联系原作者

相关文章
|
25天前
|
Java Maven
【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“
【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“
37 3
|
5天前
|
存储 网络协议 Java
本地MinIO存储服务通过Java程序结合cpolar实现远程连接上传文件
本地MinIO存储服务通过Java程序结合cpolar实现远程连接上传文件
|
7天前
|
存储 Java 开发工具
【Java探索之旅】用面向对象的思维构建程序世界
【Java探索之旅】用面向对象的思维构建程序世界
9 0
|
7天前
|
小程序 Java 程序员
【Java探索之旅】我与Java的初相识(二):程序结构与运行关系和JDK,JRE,JVM的关系
【Java探索之旅】我与Java的初相识(二):程序结构与运行关系和JDK,JRE,JVM的关系
23 0
|
7天前
|
数据采集 存储 前端开发
Nutch库入门指南:利用Java编写采集程序,快速抓取北京车展重点车型
2024年北京车展凸显电动车全球热度,中国引领市场,展出117台全球首发车,包括30台跨国公司电动车。借助Nutch库抓取汽车网站数据,分析电动车市场趋势。通过配置代理和多线程爬虫,高效收集新车信息,助力理解市场动态,推动可持续交通发展。
Nutch库入门指南:利用Java编写采集程序,快速抓取北京车展重点车型
|
8天前
|
Oracle Java 关系型数据库
Java历史简述及程序运行机制简述
Java起源于1991年Sun公司James Gosling领导的Green项目,最初命名为Oak,后因爪哇岛咖啡更名为Java。1995年正式发布,2009年Sun被Oracle收购。Java程序运行包括:开发源代码、编译成字节码、JVM翻译为平台兼容的机器码执行。
|
12天前
|
Java
网页运行java程序cheerpj
网页运行java程序cheerpj
35 0
|
13天前
|
Rust Java 编译器
面试官:说一说你的第一个Java程序是怎么跑起来的?
面试官:说一说你的第一个Java程序是怎么跑起来的?
16 3
|
13天前
|
Java Unix Linux
【Java基础】数据类型以及程序执行过程浅析
【Java基础】数据类型以及程序执行过程浅析
20 0
|
18天前
|
缓存 负载均衡 前端开发
构建高性能 Java Web 应用程序
【4月更文挑战第19天】构建高性能 Java Web 应用涉及数据库优化(合理设计、查询优化、性能调优)、缓存策略(服务器端缓存、HTTP 缓存)、代码优化(避免冗余查询、减少对象创建、有效使用线程)、异步处理(增强并发能力)、负载均衡(分发请求、提升可靠性)、性能测试与监控(发现瓶颈、实时问题)、前端优化(减少加载时间、优化资源)、服务器配置(硬件资源、系统优化)以及代码压缩和资源合并。综合运用这些技术,能显著提升应用性能和用户体验。