原来问题在这里-我的memory leak诊断历程
自从公司开始将java作为主要开发语言后,C++与java的混合应用日趋增多。 java与C++的通信主要也是使用JNI来完成,这并没有什么问题。对于这样的混合应用项目来说,最大的噩梦莫过于memory leak诊断了。由于Java的内存管理模式与C++有很大的区别,所以对这样的项目进行调试时,首先要区分是Java代码的memory leak还是C++代码的memory leak。对于内存诊断来说,我们需要先了解一些指标含义和工具的使用,这样才能做到有理有据。
指标:
memory(working set): MSDN的说明-The working set of a process is the set of pages in the virtual address space of the process that are currently resident in physical memory. The working set contains only pageable memory allocations; nonpageable memory allocations such as Address Windowing Extensions (AWE) or large page allocations are not included in the working set.
一个进程的专用工作集指的是当前进程常驻于物理内存的虚拟内存页面集。它只包含可以被分页的内存区;那些不能被分页的内存区如AWE(一种应用程序可以直接操纵大于4G物理内存的技术)或是LPA(主要用于服务器的大物理内存上,一般对于64位的系统比较有用)不会被包括在专用工作集中。
virtual bytes: 当前进程所使用的虚拟内存大小。这个指标包含所有的内存页面文件,如在磁盘交换区中的页面文件,加载的库文件等。
private bytes:当前进程已经分配的私有内存的大小,不包含共享给其他进程使用的内存。
在一般情况下,如果你的应用程序需要的内存不多,并且比较活跃,内存泄漏比较明显,那么通过监视working set就可以看出是否有内存泄漏。但是如果应用程序比较复杂,模块较多而且需要的内存在不同时刻变化比较大,那么单纯根据working set是看不出来问题的,因为一些页面文件会在某一时刻被交换的磁盘缓冲区中。那么,我们就需要去分析virtual bytes和private bytes这两个指标。但这也不是绝对准确的,因为有些时候比如内存碎片比较多,而应用程序经常请求大块连续的内存,也会造成virtual bytes增加的情况。所以,在实际环境中我们还需要了解应用程序的内存使用特点来确定是否有memory leak问题。
介绍完了指标,下面介绍一下工具:
对于Java程序来说,比较好的监视内存的工具是jvirsualVM。这个工具是java自带的,它可以监视本地或远程的java应用程序,也可以监视系统服务这样的程序。你可以在JDK的bin目录下找到。其他的还有比如jconsole, eclipse的MAT等。
对于C++的程序来说,那工具可就多了。这里我主要用的是IIS Debug Diagnostics Tool,这个原本是用于IIS应用程序的诊断工具,在监视系统服务这样的应用上还是很方便的。同时它可以进行自动的memory leak分析并生成报表。对于memory leak的诊断很有帮助。当然,我还用到了vmmap和rammap两个应用程序。这两个程序原先是system internal那个作者开发的,现在已经收归微软门下了。这两个文件一个用于查看进程的虚拟内存分配情况,而另一个拥有查看物理内存的时候情况。最后一个工具就是process hacker,它能帮助我们更详细的了解进程的内存分配,句柄分配,模块加载,线程数目等。当然processexplorer也可以做相同的工作,但是如果你要查看内存块的内容时,还需要windbg的配合。
基本上我们需要的东西已经都有了,那么接下来就是真正的调试之旅了。这里我先介绍一下我要调试的程序是基于tomcat的企业级备份服务,java的工作是基于c++模块上来做的统计和管理工作。对于这样一个应用,memory leak是一个很头疼的问题,因为基本上不能通过调试来解决。那么如果出现了memory leak,我们先要区分出来是java代码还是c++代码。因为java是具有垃圾回收机制的语言,所以memory leak比较不好检查。那么对于java来说什么样的情况才是memory leak呢? 某个对象不能被回收,就是一个leak,比如object被放在了一个singleton的列表中,只要这个singleton没有被释放,那么这个object永远存在于内存中。对于tomcat程序来说,我们需要先配置几个参数用于jvisualvm的监视:
-Dcom.sun.management.jmxremote.port=8086
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
这样就可以在jvisualvm里面建立一个JMX的连接用于tomcat,然后我们需要在不同的时间点去打heap dump,然后通过比对两个时期的对象变化来检查是否发生memory leak。这里需要你对你的应用程序对象分配比较了解才行。在java这块对于内存来说需要关注的主要是heap和PermGen,heap是new对象要用的,而PermGen是存放class和meta data的内容。

经过不懈的努力,最终发现我们程序中对http connection没有设置超时,从而导致在持久化连接模式下,很多访问web service的线程会hang住。整完了Java部分的memory leak问题,就该整C++模块的问题了。通过一段时间的观察发现,working set的大小会在某一时刻降下来,但是virtual bytes和private bytes是阶段性的上涨。这说明可能是某段代码请求大块内存而产生的,但是这并不能证明是leak。而且这段代码也不一定是在C++中。为了找到问题是在C++中还是Java中,我需要对java的内存使用情况进行跟踪(这里使用到了process hacker的内存检查功能)。

最终我发现java部分的虚拟内存没有变化,一直维持在我们设定的最大内存大小之内。这样我们就可以从C++这边开始工作了。先用vmmap查看一下内存的使用情况,发现在一个地方内存读写量非常大,这证明有程序非常的密集访问某块内存。接下来就是使用Debug Diagnostics Tool对Tomcat的service进行跟踪了. 先创建一个memory leak的规则,然后开始跟踪。在一段时间后,内存出现比较大的变化后,选择memory dump并进行自动分析。你会得到一个大概的内存分析报告,并且报告会给出可能的memory leak模块。根据这个信息你就有选择性的去检查某个模块的代码来确定是否真的发现leak了。

最终发现问题是在加密解密函数出来问题,在一个函数中malloc了一块内存用于存储字符串,然后将它加密完后,拷贝到新的加密完的内存中就直接返回了,没有去free它。而是在返回的代码后面去free。这样就造成了每一次成功的加密就会泄漏一块内存,因为加密函数只在特定的时候被调用,所以内存成阶段性的上涨。
到这里,整个诊断memory leak的过程也就结束了。我的感受是搞这种问题既要有技术也要有运气^_^ ! (以上的图是现找的,不说明真实情况,所以大家看看知道个样子就可以了)
涉及到的工具通过google都可以找到。
原来问题在这里-我的memory leak诊断历程的更多相关文章
- Android 内存管理 &Memory Leak & OOM 分析
转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...
- quartz集群报错but has failed to stop it. This is very likely to create a memory leak.
quartz集群报错but has failed to stop it. This is very likely to create a memory leak. 在一台配置1核2G内存的阿里云服务器 ...
- 山东省第七届ACM省赛------Memory Leak
Memory Leak Time Limit: 2000MS Memory limit: 131072K 题目描述 Memory Leak is a well-known kind of bug in ...
- caching redirect views leads to memory leak (Spring 3.1)
在Spring 3.1以及以下版本使用org.springframework.web.servlet.view.UrlBasedViewResolver + cache(如下配置),在会出现任意种re ...
- 一则JVM memory leak解决的过程
起因是我们的集群应用(3台机器)新版本测试过程中,一般的JVM内存占用 都在1G左右, 但在运行了一段时间后,慢慢升到了4G, 这是一个明显不正常的现象. 定位 过程: 1.先在该机器上按照步骤尝试重 ...
- Linux C/C++ Memory Leak Detection Tool
目录 . 内存使用情况分析 . 内存泄漏(memory leak) . Valgrind使用 1. 内存使用情况分析 0x1: 系统总内存的分析 可以从proc目录下的meminfo文件了解到当前系统 ...
- SilverLight - Memory Leak
There is a memory leak issue in current silverlight project. It occurs in the search function: the m ...
- A memory leak issue with WPF Command Binding
Background In our application, we have a screen which hosts several tabs. In each tab, it contains a ...
- quartzScheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak解决
01-Jul-2016 07:24:20.218 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 80 ...
随机推荐
- POJ 2856 Y2K Accounting Bug【简单暴力】
链接: http://poj.org/problem?id=2586 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26733#probl ...
- 关于logback
1 logback是一个日志框架 2 logback的构成 LogBack被分为3个组件,logback-core, logback-classic 和 logback-access. 其中logba ...
- Django 动态导入配置文件的类
导入配置文件的类 #如何用字符串的形式动态导入模块 from importlib import import_module path=''api.cors.CORSMiddleware' #CORSM ...
- git克隆远程分支
$ git branch –r 查看远程branch信息 $ git checkout origin/dev检出远程分支 $ git branch -a 查看所有分支,包括本地和远程 可以使用chec ...
- PHP 提高PHP性能的编码技巧以及性能优化
0.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这 么做,它是 一种可以把多个字符串当作参数的“函数”(译注:PHP ...
- 使用OpenSSL工具制作X.509证书的方法及其注意事项总结
版权声明:本文为博主原创文章.转载请注明出处. https://blog.csdn.net/Ping_Fani07/article/details/21622545 怎样使用OpenSSL工具生成根证 ...
- [转载]Java web应用中的常见字符编码问题的解决方法
以下是 Java web应用的常见编码问题 1. html页面的编码 在web应用中,通常浏览器会根据http header: Content-type的值来决定用什么encoding, 比如遇到Co ...
- 正则表达式 匹配符合A表达式切不符合B表达式的字符串
有一道这样的面试题 写一个Java方法,利用正则表达式判断输入str中包含字符串”ios“或”apple“(大小写不敏感),但不包括”mediaplayer“.如果满足条件,返回所包含的字符串”ios ...
- LeetCode:贪婪算法
LeetCode:贪婪算法 贪婪算法基础 我 717. 1-bit and 2-bit Characters class Solution { public boolean isOneBitChara ...
- 【LeetCode】【动态规划】Generate Parentheses(括号匹配问题)
描述 Given n pairs of parentheses, write a function to generate all combinations of well-formed parent ...