干货:一次内存泄露的实战分析过程

一、背景介绍

最近在做日志服务的稳定性测试,大约跑一个小时左右一直报OOM,使用的测试java代码结构跟NDIR稳定性测试使用的基本上是一致的,但是NDIR稳定性测试做过很多次了,没有出现过类似问题,由于急着做稳定性测试,这个事情让我很头疼,于是花了一些时间去分析了一下内存情况。

二、问题分析

1.为什么NDIR可以使用,日志服务却不可以?

我是这么分析的:

第一,我考虑了两种稳定性测试请求情况的差别,主要是从并发线程数目、tps值以及交互的数据量出发,发现两个测试框架的线程数目以及请求时实际的tps值大致是一个量级的,而交互的数据量差别很大,表现出来的情况是日志服务这边打印的日志量过大,基本上是NDIR那边10倍以上的日志量。

第二,我考虑了两种稳定性测试配置上的差异,主要是从机器配置、mvn配置、jvm配置情况出发,发现这个方面是配置是一样的,测试机器都是同一个。

第三,我考虑两种稳定性测试代码以及数据结构的差异,发现代码结构以及使用的数据结构也都是差不多的,没有发现什么特殊地方。

所以,可能导致日志服务出现问题的地方最有可能的地方就在交互数据量以及日志量,但是日志系统使用的是log4j,是一个很成熟的工具,应该没有问题。

2.运行时大量消耗内存的到底是什么?

带着上面的初步分析,我开始进行了内存排查这个使内存oom的对象到底是什么。

首先看看我mvn的配置贴出来:<argLine>-Dfile.encoding=UTF-8 -Xms512m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512M</argLine>

再看看实际运行时jvm情况:

实际机器分配的jvm参数与设置的一致,并且perm消耗值在不断的长大。

再看看perm情况以及历史上消耗内存情况:

从图上可以看出消耗内存最多是是一个class [B的对象有4852个对象,如果能知道这个类是什么,那么就可以对症下药消灭它了。关键是这些jdk自带的一些工具不直观,看不出来是哪些类的对象,于是使用了更为直观的大名鼎鼎的eclipse的插件MemoryAnalyzer来分析内存情况。

从这个图中清晰看到基本上都是ByteArrayOutputStream这个类的对象将内存消耗尽了,那我们知道log4j写日志以及maven打印console都是使用这个类的,于是打开去看看。

从这个图中可以很清楚的看出,org.apache.maven.surefire.report.ReporterManager的consoleCapture方法消耗了其中的一半,也就是说console就占用了其中的一半内存,总共512M的term被这个console打印占去了260M,那剩下的肯定就不够用了,而且这些byte[]是持久不释放的,那么不管你有多少内存,只要运行时间够长一定会将内存耗尽的。而这个时候去log4j的配置文件看一下发现:

那么情况就水落石出了,也能很好的解释为什么同样的稳定性测试框架NDIR能很好的运行日志服务就不可以,原因是NDIR那边打印的日志量太小,三天到五天的稳定性测试不足以触发perm的512M大小内存OOM的上限,如果继续一直跑下去相信也是会发生OOM的情况的。花费了两天和一个晚上的时间终于把问题解决了,这种成就感真的是比发薪水还要爽上N倍。

3.怎么解决?知道问题的原因后,解决问题就很简单了。第一种方法,跑稳定性测试的时候去除console配置,这样就不会有这种情况的发生。第二种办法,大力的减少日志打印量,这样可以跑的时间久很多,但是治标不治本。

三、总结

在我们实际的测试过程中可能会遇到很多的问题,这里总结为四点:

1.增强分析问题的能力。

2.增强掌握的知识和技能,学为所用。这是一个积累的过程,不要怕麻烦,慢慢积累知识和工具,试着去解决自己遇到的问题,感觉慢慢会有收货。在这里解决这个问题带来的那种感觉真的很棒。

3.我觉得遇到问题时,不要急于去做,留一些时间去思考也许结果会更好。在遇到这个问题的时候,因为是着急着上线,着急着做稳定性测试,所以就急忙着调试,各种尝试以及去网上搜集资料,但始终没有解决问题还花费掉一天一夜的时间,也没有什么收货,而第二天就静下心来去分析问题,然后借助工具去排查问题,结果半天就解决了。

不定期发布有态度不忽悠的靠谱的文章,有内涵,有节操。

喜欢的朋友欢迎关注和转发

本文章为作者原创

??禁止??

其他公众账号转载,若有转载,请标明出处

时间: 2024-10-24 22:14:02

干货:一次内存泄露的实战分析过程的相关文章

Activity内部Handler引起内存泄露的原因分析

有时在Activity中使用Handler时会提示一个内存泄漏的警告,代码通常如下: public class MainActivity extends Activity { private TextView tvHelloWorld; private Button btnSetText; private Handler mHandler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) {

一个内存泄露问题的分析和处理(一)

关于内存泄露的问题,之前遇到过一次,当时的应用场景是这样的: 生产环境的oracle分为两个RAC,需要做单点故障的测试,就把其中的一个RAC给停掉了,看看程序能否连接到另外一个RAC.有一个程序在这种情况下,出现了内存泄露的情况,内存疯狂增长,最终内存耗尽,导致业务主机宕机.后来派出框架部门和业务部门一起来分析,最终得出的结论是由于数据库连接没有释放导致数据处理时,一直在使用一个失效的连接,所以不断抛出OTL的异常. 大概的逻辑是这样的,程序启动时,会对每一个数据库的做一个连接池,当需要数据库

一个内存泄露问题的分析和处理(二)——valgrind工具的用法

valgrind是linux下对C++和C程序进行内存泄露检测的工具,除了内存检测,valgrind还提供了很多其他的功能,这里主要介绍下valgrind的内存检测的功能. 首先是文件的下载,valgrind的官方网址是http://valgrind.org/,最新版本的valgrind是3.9,下载地址如下:http://valgrind.org/downloads/.下载好的文件是tar.bz2格式的文件--valgrind-3.9.0.tar.bz2,linux下可以使用tar命令对压缩包

JVM内存管理概述与android内存泄露分析

一.内存划分 将内存划分为六大部分,分别是PC寄存器.JAVA虚拟机栈.JAVA堆.方法区.运行时常量池以及本地方法栈. 1.PC寄存器(线程独有):全称是程序计数寄存器,它记载着每一个线程当前运行的JAVA方法的地址, 如果是当前执行的是本地方法,则程序计数器会是一个空地址.它的作用就是用来支持多线程,线程的阻塞.恢复. 挂起等一系列操作,直观的想象一下,要是没有记住每个线程当前运行的位置,又如何恢复呢.依据这一点, 每一个线程都有一个PC寄存器,也就是说PC寄存器是线程独有的. 2.JAVA

【转】.. Android应用内存泄露分析、改善经验总结

原文网址:http://wetest.qq.com/lab/view/107.html?from=ads_test2_qqtips&sessionUserType=BFT.PARAMS.194206.TASKID&ADUIN=554147273&ADSESSION=1467939955&ADTAG=CLIENT.QQ.5479_.0&ADPUBNO=26582 前言   通过这几天对好几个应用的内存泄露检测和改善,效果明显: 完全退出应用时,手动触发GC,从原来占有

java内存泄露

Java是如何管理内存 为了判断Java中是否有内存泄露,我们首先必须了解Java是如何管理内存的.Java的内存管理就是对象的分配和释放问题.在Java中,程序员需要通过关键字new为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间.另外,对象的释放是由GC决定和执行的.在Java中,内存的分配是由程序完成的,而内存的释放是有GC完成的,这种收支两条线的方法确实简化了程序员的工作.但同时,它也加重了JVM的工作.这也是Java程序运行速度较慢的原因之一.因为,G

移动端测试===Android内存泄露和GC机制(转)

本文转自:https://www.testwo.com/article/1153 1.前言 Hello,小伙伴们,相信大家在项目测试中都遇到过内存泄露问题,小编也着实爬过很多坑.比如小编所测项目,更换了多实例版本的sdk,横竖屏切换后有MapView没有销毁,导致内存泄露.小编测试手表项目,因为手表内存有限,测试中常遇到应用无响应或者闪退,故而小编对GC机制进行了进一步学习了解. 本文先对Android内存垃圾回收机制进行介绍,之后对分析.定位内存泄露常用的测试方法进行总结,分享给大家. 2.A

Java垃圾回收机制以及内存泄露

1.Java的内存泄露介绍 首先明确一下内存泄露的概念:内存泄露是指程序运行过程动态分配了内存,但是在程序结束的时候这块内存没有被释放,从而导致这块内存不可用,这就是内存 泄露,重启计算机可以解决这个问题,但是有可能再次发生内存泄露,内存泄露与硬件没有关系,它是软件设计的缺陷所导致的. Java发生内存泄露的原因很明确,就是长声明周期对象持有短声明周期对象的引用就很可能发生内存泄露.尽管短生命周期对象已经不再需要,但是因为长生命 周期对象在持有它的引用而导致它不能被GC回收,这就是Java内存泄

Android 性能优化之使用MAT分析内存泄露问题

我们平常在开发Android应用程序的时候,稍有不慎就有可能产生OOM,虽然JAVA有垃圾回收机,但也不能杜绝内存泄露,内存溢出等问题,随着科技的进步,移动设备的内存也越来越大了,但由于Android设备的参差不齐,可能运行在这台设备好好的,运行在那台设备就报OOM,这些适配问题也是比较蛋疼的,比如我们平常运行着一个应用程序,运行的好好的,突然到某个Activity就给你爆出一个OOM的错误,你可能会以为是这个Activity导致的内存泄露,你会想到也有可能是内存有泄露吗?内存泄露就像一个定时炸