想要轻松解决Jvm堆内存溢出?JProfiler利器来支招!

存储架构 2017-06-23

很多应用程序使用Log4j记录日志,如何使用Kafka实时的收集与存储这些Log4j产生的日志呢?一种方案是使用其他组件(比如Flume,或者自己开发程序)实时监控这些日志文件,然后发送至Kafka。而另外一种比较便捷的方案是使用已封装Kafka的Log4jAppender:只需在Log4j配置文件中进行简单配置,即可完成将Log4j产生的日志实时发送至Kafka中。

但在log4j推送kafka程序的过程中,因log4j其对底 层封装的比较好,底层的队列和内存管理对开发者几乎透明,导致使用过程中对出现的内存溢出定位带来一定的障碍。

【现场还 原】

某柜台产生了一大批历史日志文件,用户希望把这部分历史数据进行深度分析:如用户的购买情况,用户交易的集中时间频率等,进行潜在价值挖掘。但在模拟用户现场导入历史数据的过程中,当历史数据的数量超过一定阀值时(测试数据为800百万),就会出现jvm堆内存不够的异常。

▪ 启动命令如下:

▪ 运行过程中出现如下错误:

【异常定 位】

引入利器:JProfiler

JProfiler 引入jvm内存排查定位工具, 追踪内存的泄露问题。

JProfiler把CPU、执行绪和内存的剖析组合在一个强大的应用中,可提供许多IDE整合和应用服务器整合用途,是一个独立的应用程序,但提供Eclipse和IntelliJ等IDE的插件。它允许两个内存剖面评估内存使用情况和动态分配泄漏和CPU剖析,以评估线程冲突。

异常定位

首先,调整启动命令行,把内存的溢出信息输出到本地:

然后,打开“JProfiler”分析工具,把.hprof结尾的日志导入分析:

最后,JProfiler工具中分析的结果如下:

【问题剖析

通过jprofile工具能快速定位到占用内存最大的类,从中

知道Log4jEventWrapper这个内部类使用中出现了错误。

如上图中红线最长的类:

为了追踪具体的代码,通过IntelliJ idea等开发工具进行log4j的源码追踪来进一步定位问题:

▪ 首先根据jprofile的提示,已经明确哪个类占用了最大内存:

通过阅读该内部类:Log4jEventWrapper,发现其有被外部初始化所调用的方法,如下图:

然后在initDisruptor进行源码上设置断点,进行单步调试测试;

通过单步调试,发现在calculateRingBufferSize()方法,有个设置默认属性值的操作,如下所示:

这里发现底层实现时,如果没有设置系统参数,默认会给 ringBufferSize设置值:262144条。

到这里猜测可能是ringBufferSize值默认得过大,即本地缓存数据过多导致申请的jvm不够用。可以重新梳理流程,大致过程如下:

【解决方法】

调参及测试

修改启动脚本,并修改默认的RingBufferSize条数大小,往小的数量调整:

把RingBufferSize设置较小值(如4096时),经过测试对于历史数据采集没有出现再内存溢出,也没有出现缓存较小出现超时数据丢失的问题,基本断定是RingBufferSize过大造成的堆内存溢出。但具体配置RingBufferSize多小合适,以及太小所带来的影响内容,笔者尚未验证,待后续有机会再把log4j的源码再进行深入阅读及调试,再继续分享。

【小 结】

对于java调用过程中,可以通过如下步骤进行堆内存溢出定位:

▲ 在java启动命令中,增加:

-XX:+HeapDumpOnOutOfMemoryError,当出现内存溢出时,会在当前目录下产生.hprof的日志文件,具体命令参照如下:

通过Jprofile把对应.hprof文件导入分析,确定内存溢出的类。

结合Eclipse或IntelliJ idea等开发工具进行源码追踪,来定位最终导致内存溢出的问题。

Jprofile安装使用,参考网址:

http://blog.csdn.net/shiyong1949/article/details/52574896

恒生技术之眼原创文章,未经授权禁止转载。详情见(点击) 转载须知

恒生技术之眼

责编内容by:恒生技术之眼 (源链)。感谢您的支持!

您可能感兴趣的

Setting up Kafka on a Raspberry Pi cluster via Ans... After installing Docker and Kubernetes on my RPi cluster , I wanted to go on, with Kafka. P...
Error when sending message to topic test with key:... windows下使用kafka遇到这个问题: Error when sending message to topic test with key: null, value: 2 bytes with ...
Creating an IoT Kafka Pipeline in Under Five Minut... In a recent MemSQL webcast, we discussed how modern enterprises can easily adopt new data management...
ClassNotFoundException和NoClassDefFoundError的区别... 在写Java程序的时候,当一个类找不到的时候,JVM有时候会抛出ClassNotFoundException异常,而有时候又会抛出NoClassDefFoundError。看两个异常的字面意思,...
JVM加载、启动和初始化 这实际上是 《The Java ® Virtual Machine Specification - Java SE 8 Edition》 中第五章内容(Loadin...