原来问题在这里-我的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 ...
随机推荐
- EhCache 集群 配置(RMI方式)
这里先说明下环境:JDK1.6.ehcache-core-2.1.0.jar.Tomcat6.Spring3.0.2.使用的是RMI方式配置集群的,这里先吐槽下遇到的情况,在搜相关知识的时候发现到处都 ...
- linux shell脚本: 自动监控网站状态并发送提醒邮件
1.创建监控脚本:$ vi /alidata/shell/webcheck.sh #!/bin/sh weblist="/alidata/shell/weblist.txt" my ...
- PHP自定义函数: 下载远程文件
function httpcopy($url, $file="", $timeout=60) { $file = empty($file) ? pathinfo($url,PATH ...
- Python中pymysql模块详解
安装 pip install pymysql 使用操作 执行SQL #!/usr/bin/env pytho # -*- coding:utf-8 -*- import pymysql # 创建连接 ...
- [ACM] FZU 2087 统计数边 (有多少边至少存在一个最小生成树里面)
Problem Description 在图论中,树:随意两个顶点间有且仅仅有一条路径的图. 生成树:包括了图中全部顶点的一种树. 最小生成树:对于连通的带权图(连通网)G,其生成树也是带权的. 生成 ...
- mac上傻瓜式java安装环境配置
适用于mac新手用户或者黑苹果用户 首先,打开终端 输入 java -version 检查是否已安装好Java运行环境 显示我现在电脑没有安装 如果返回版本号,说明运行环境成功 对于windows用过 ...
- .net序列化与反序列化——提供多次存储对象集后读取不完全解决方案
||问题: 文本文档读取序列化文件时只能读取第一次序列化对象或对象集,而多次序列化存到同一个文本文件中不能完全读取.最近做一个简单的学生管理系统,涉及到多次将学生对象序列化后追加存储到同一个文档中.在 ...
- js之定时器
一.通过定时器我们可以间隔设定时间重复调用某个函数,利用这个特性,我们可以做很多事,例如,12306上的每间隔5秒查询自动查询一次余票,简单动画的实现等等 二.定时器的格式: 定时器有两种格式,分别是 ...
- python详细目录
python第一篇 第二篇.初识列表字典元祖循环 第三篇.内置方法 第四篇.编码解码 列表.元祖 第五篇.数据类型 第六篇 函数 第七篇.函数二 第八篇.递归.装饰器 第九篇 正则表达式 第十篇.模块 ...
- hiho一下 第四十八周 拓扑排序·二【拓扑排序的应用 + 静态数组 + 拓扑排序算法的时间优化】
题目1 : 拓扑排序·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒.这事在校内BBS上立刻引起了大家的讨论,当 ...