项目场景:
java做了一个爬虫项目,功能实现了。
问题描述
但是每运行一次,内存就增加2%。然后直到服务器触发自我重启,如此往复。直到运维受不了了,所以打算花时间研究研究这个老古董了。
原因分析:
从结果上看很清晰了,就是内存只涨不消,一定是没有触发到gc。然后就选择了所有怀疑的地方都加上内存的使用情况,观察一下到底是哪里的问题。
解决方案:
项目里使用到的功能点有
- openapi
- 百度OCR识别验证码
- 爬取三方网站
- html内容解析
先查了一下,这么加内存分析,代码的方式如下,这里可以查看到对应此时jvm使用到的内存数量
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
log.debug("xxx Used Memory start: " + usedMemory / 1024 / 1024 + " MB");
// 这里是要监听的方法
totalMemory = runtime.totalMemory();
freeMemory = runtime.freeMemory();
usedMemory = totalMemory - freeMemory;
log.debug("xxx Used Memory end: " + usedMemory / 1024 / 1024 + " MB");
所以在上边涉及到的四个内容点都加上了这个日志,结果输出的发现了问题出现在4.html解析那段上,其它都没有问题。
所以搜了一下,还真有解决方案,感谢
https://www.5axxw.com/questions/simple/1earac
所以最终的解决方案就是手动调用empty方法。最终的问题就是调用了这里会导致内存问题
Parser.parse(html, "");
Document parse = Jsoup.parse(html);
try {
String message = parse.select("#message").val();
if (!StrUtil.isBlank(message) && !message.toUpperCase().contains("SUCCESS")) {
throw new SpiderBusinessException("XXX_EXCEPTION", message);
}
} catch (Exception ignored) {
} finally {
parse.empty();
}
这个地方是明确用了Parser.parse(html, “”);
代码里还有一个地方,没有明确调用这个方法,是引用了 jspoon,这里调用了Parser.parse(html, “”);
所以这个地方的解决方式,就得换一种方式,就是需要采用上边解决方案4,手动gc
try {
xxx = jspoon.adapter(XXX.class).fromHtml(html);
} catch (Exception ignored) {
} finally {
System.gc();
}
至此,问题解决。
这里也多啰嗦一下,运行System.gc()方法会显示进行Full GC,其实不然,运行System.gc()只是提醒JVM的垃圾回收器执行GC,但是不确定是否马上执行GC。
参考
gc