`
donsun
  • 浏览: 30011 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java系统内存泄漏分析

阅读更多

Java系统内存泄漏分析报告



 1    概述    2
1.1    背景    2
2    Java内存泄漏    2
2.1    Java是如何管理内存    2
2.2    什么是Java的内存泄漏    2
2.3    如何跟踪Java内存泄漏    3
3    调查内容    4
3.1    环境配置    4
3.1.1    安装JRockit JDK 1.4    4
3.1.2    修改Eclipse默认JRE为JRockit    5
3.1.3    修改部分源码使其适应JDK1.4标准    5
3.1.4    修改JVM才参数,开放JMX调试服务    6
3.1.5    配置BEA JRockit(R) Mission Control连接    6
3.1.6    跟踪资源使用情况    7
3.2    PC端功能    7
3.2.1    ThreadLocal缓存对象生命周期跟踪    7
3.2.1.1    修改方式    9
3.2.2    Session对象回收周期过长    9
3.2.2.1    修改方式    9
4    参考资料    10

 

1    概述

1.1    背景

X项目中系统使用过程中,运行时间过长出现内存资源持续占用不能被及时回收的情况,并且其资源占用量随运行时间与并发性成正相关,初步判断为Java内存泄漏导致,所以进行内存泄漏方面的调查分析。

2    Java内存泄漏

2.1    Java是如何管理内存

Java通过GC功能不定时地回收内存资源,GC判断一个对象是否可以回收的标准是该对象是否可达,即是否被引用,JVM在以有向图的方式管理所有堆上资源,这使环形循环引用的不可达对象依旧可以被有效的回收,下图简单的描述了一个可回收单元的产生。
 

2.2    什么是Java的内存泄漏

熟悉C/C++语言的开发人员都知道,C/C++语言的内存泄漏指的是不可回收资源,是纯粹的内存黑洞,除非进程终止后操作系统回收进程所有堆上资源时才会被释放,这是纯粹的内存泄漏;而Java语言的内存泄漏与C/C++语言所指的内存泄漏非同一概念,Java语言所指的内存泄漏是指全局/静态集合持续被持有而导致的无用单元不可回收,是一种逻辑上的“内存泄漏”。


2.3    如何跟踪Java内存泄漏

很多应用服务器厂商都提供了功能强大的GC跟踪工具,用于分析堆上内存分配与收集情况,从而确定内存泄漏位置。本次调查采用的是BEA公司发布的“BEA JRockit(R) Mission Control 2.0”。开发人员试用版本许可可以使用1个小时。
使用BEA JRockit(R) Mission Control 2.0所包含的如下三个工具辅助内存泄漏分析:
BEA JRockit Management Console
 

 
BEA JRockit Runtime Analyzer (JRA)
 

 
BEA Memory Leak Detector
 

 
具体使用方法,参考BEA官方网站说明。

3    调查内容

3.1    环境配置

3.1.1    安装JRockit JDK 1.4

BEA官方网站下载开发人员试用版本的JRocket JDK工具包jrockit-R27.2.0-jdk1.4.2_13,安装后导入试用版本许可文件,使用版本可以免费使用1个小时,重新启动可以继续使用。
导入试用许可证:
<C:\Program Files\Java\jrockit-R27.2.0-jdk1.4.2_13\jre>

<?xml version="1.0" encoding="ISO-8859-1"?>

<bea-licenses>
    <license-group format="1.0" product="JRockit" release="*">
        <license
            component="JRA"
            cpus="unvalued"
            expiration="never"
            hours="1"
            ip="any"
            licensee="BEA Evaluation Customer"
            serial="454493271161-2222564495787"
            type="SDK"
            signature="MC0CFFCnVsUSP96Xd5YtNPTQKXcGoiBgAhUA4yH2/UmqYpJLNzPOPmJUdqPUrNs="
        />
        <license
            component="Memory Leak Detector"
            cpus="unvalued"
            expiration="never"
            hours="1"
            ip="any"
            licensee="BEA Evaluation Customer"
            serial="454493271161-2222564495787"
            type="SDK"
            signature="MCwCFFVySk0b0fwMReywZt4UyBZX7PjEAhQibfVzVVDZgkXgnMxZUfFzAS5gew=="
        />
    </license-group>
</bea-licenses>

 

3.1.2    修改Eclipse默认JRE为JRockit


3.1.3    修改部分源码使其适应JDK1.4标准

  • 关于JDBC的接口定义在1.4标准中增加了若干接口,实现即可。
  • PublicKey验证时从磁盘系统读入序列化后的1.3类时出错,调试时使其跳过,始终返回true。

3.1.4    修改JVM才参数,开放JMX调试服务

 

3.1.5    配置BEA JRockit(R) Mission Control连接

 

3.1.6    跟踪资源使用情况


3.2    模块分析

3.2.1    ThreadLocal缓存对象生命周期跟踪

LoginUser用于提高系统性能的缓存对象,缓存内容包括,用户信息,商品信息,分页信息等。按照设计者的初衷,其生命周期的可控制范围为Session, 当用户注销或Session超时后会被移出,内存资源会被回收。
但是,在LoginUser中引入了ThreadLocal的静态成员,用于缓存当前登录用户的LoginUser对象,其生命周期与当前线程绑定,请求完成后并没有从ThreadLocal中销毁,而滞留于静态存贮区域,当用户注销后,该对象仍然无法被销毁,从而使LoginUser对象生命周期失控,直至该线程再次被分配时才会被新的对象覆盖,使其区域不可达。当同一个用户的请求被多次提交时该对象的引用将会逐渐的产生更多的引用,从而更难于销毁。多用户登录注销后,会导致更多的无效内存无法回收。
跟踪过程:

  • 用户登录,创建LoginUser对象


 

对象引用关系(请放大观看)



 
LoginUser对象被两个集合引用,分别为Session和ThreadLocal。经过若干页面操作后,ThreadLocal集合中的引用会逐渐增多,从而使对象生命周期更加难于控制。

  • 用户注销,企图销毁LoginUser


如上图所示,LoginUser被从Session中清除,但是ThreadLocal中的引用一直存在,并且其引用数目不可控制,可能会很多,引用数目越多其生命命周期可能会更长。从而导致内存泄漏。

3.2.1.1    修改方式

将LoginUser对象与Resource对象的ThreadLocal引用周期控制在Servlet请求周期之内,但此请求完成后,释放其对对象的引用,使其始终保持Session的单一引用,即可严格控制集合对象的生命周期。
Servlet

public void doGet(HttpServletRequest req, HttpServletResponse resp)
 throws ServletException, IOException {
	try
{

License license = new License();
HtmlPage page = null;

.........
.........
.........
}
//      add for clear memory leak /begin
finally
{
LoginUser.setCurrentLoginUser(null);
ResourceManager.setBundle(null);
}
//      add for clear memory leak /end
}
 

3.2.2    Session对象回收周期过长

相同的用户多次登录系统而不注销的情况下,先登录的用户的Session以及LoginUser对象会多次被创建,而不能及时的被清除,这给峰值操作时的资源占用带来了隐患,由于用户基本上没有注销的习惯(通常情况下,用户都是直接关闭浏览器的),Session的超时时间通常是30分钟,那么这部分对象将在30分钟后才能被回收。
由于LoginUser中的对象可能会很大,由此所带来的内存消耗是非常大的,又因为同一个用户多次登录,LoginUser没有必要重复创建。

3.2.2.1    修改方式

1.    将系统主窗口中增加关闭事件,关闭时产生注销操作。
a)    优点:
i.    可以缩短Session中的LoginUser无用生命周期,使资源第一时间被回收。
ii.    用户使用更加安全,不会因为忘记注销而产生安全漏洞。
b)    缺点:
i.    如果用户习惯了关闭主窗口然后使用子窗口进行操作,将会导致Session无效,比如:登陆后用户进入报告登录,然后关闭驻窗口进行报告登录等。
ii.    浏览器关闭时间不可靠,可能不会被调用。
2.    重复用户登录处理Session的销毁
a)    原则上讲,Serviet不允许当前Session销毁其他的Session,但是有一个解决办法,可以使用接口HttpSessionListener编写自己的侦听器,接口方法如下: 

void   sessionCreated(HttpSessionEvent   se)
void   sessionDestroyed(HttpSessionEvent   se)

  通过HttpSessionEvent可以获取每个创建的session信息   
web.xml中定义   
  	<listener>   
<listener-class>loginuser.ContextListener</listener-class>  </listener>   
 

4    参考资料

  • Java的内存泄漏

http://www-128.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/

  • JRockit Memory Leak Detector released

http://dev2dev.bea.com/blog/sla/archive/2005/06/jrockit_memory.html

  • BEA JRockit 1.4.2

http://commerce.bea.com/products/weblogicjrockit/1.4.2/142_x.jsp?

  • Developer license download(This license is free and allows the tools to be used for 1 hour, after which JRockit must be restarted before running the tools again)

http://commerce.bea.com/downloadproduct.jsp?family=JRMC&major=2.0&minor=0&delivery=1&os=All&intent=purchase

  • ThreadLocal

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html

  • 大小: 55.4 KB
  • 大小: 48.7 KB
  • 大小: 49.7 KB
  • 大小: 64.6 KB
  • 大小: 63.6 KB
  • 大小: 45.8 KB
  • 大小: 94.7 KB
  • 大小: 43.3 KB
  • 大小: 72.3 KB
  • 大小: 49.3 KB
  • 大小: 21.2 KB
  • 大小: 18.9 KB
分享到:
评论

相关推荐

    详细介绍Java的内存管理与内存泄露

    详细介绍Java的内存管理与...经过分析Java内存泄漏是破坏系统的主要因素。这里与大家分享我们在开发过程中遇到的Java内存泄漏的检测和处理解决过程. 本文先介绍Java的内存管理,以及导致Java内存泄露的原因。 ........

    java内存泄露深度分析及解决

    尽管java虚拟机和垃圾回收机制管理着大部分的内存事务,但是在java软件中还是可能存在内存泄漏的情况。的确,在大型工程中,内存泄漏是一个普遍问题。避免内存泄漏的第一步,就是要了解他们发生的原因。这篇文章就是...

    java 内存dump分析和thread dump(java core)分析

    包括 堆内存dump分析工具和thread dump(java core)的分析工具 还包括两篇关于dump分析的文档,分析java系统内存泄露死循环等非常需要啊有木有

    Android平台下井下安全监控系统内存泄露分析

    Android平台下井下安全监控系统存在内存泄露问题。经过分析认为Java内存泄露是破坏系统的主要因素。文章着重介绍了在Android平台下开发应用程序中,内存泄露出现的原因及相应的解决办法,并通过示例程序进行说明。

    Cloud_Foundry中Java应用集合类内存泄漏检测_叶瑞浩.caj

    系统首先收集垃圾回收事件后的应用内存数据,确定进行内存泄漏分析的时间 区间。然后通过收集每次垃圾回收事件后对象之间的引用关系和对象内存大小, 计算得到集合类对象的内存影响值。接着通过修改字节码的...

    Java系统中内存泄漏测试方法的研究

    全文通过与C++中的内存泄漏问题进行对比,讲述了Java内存泄漏的基本原理,以及如何借助Optimizeitprofiler工具来测试内存泄漏和分析内存泄漏的原因,在实践中证明这是一套行之有效的方法。问题的提出笔者曾经参与...

    MAT(Memory Analyzer Tool)内存分析工具的安装与使用

    MAT是分析Java堆内存的一个工具,全称是 The Eclipse Memory Analyzer Tool,用来帮助分析内存泄漏和减少内存消耗。使用MAT分析Java堆快照,可以快速计算出对象的保留大小(Retained Sizes),查找到阻止对象被回收...

    内存泄漏处理.doc

    在一个大型的JAVA系统中,内存泄露问题是最难查找和解决的问题之一。因为从异常信息无从得知到底是系统中那一部份出现了内存泄漏,只有通过对代码进行走查,使用jprofiler等调试工具察看运行时内存分配情况等手段...

    JAVA性能瓶颈和漏洞检测

    识别内存泄漏:通过易用的两步分析,跟踪运行时的内存增长; Memory Instance Calculator:计算内存泄露量; 智能化内存分析:通过Leak Doctor发现可能的内存泄露源; Aggregate Memory Footprint:理解对象创建...

    分析Android内存泄漏的几种可能

    真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。...

    Node.js中内存泄漏分析

    内存泄漏(MemoryLeak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。如果内存泄漏的位置比较关键,那么随着处理的进行可能持有越来越多的无用内存,这些无用的内存变多会引起服务器响应速度变慢,...

    Java问题定位技术.pdf

    3.Java内存泄漏分析和堆内存设置 4.关于并发和多线程 5.幽灵代码 6.常见的Java泥潭 7.JVM 8.关于字符集与编码 9.常用分析工具 10.Java最佳实践 11.关于数据库 12.工程实践 13.常见的案例 附录 A JProfiler内存泄漏...

    WebSphere应用服务器内存泄漏探测与诊断工具选择最佳实践

    内存泄漏探测和诊断步骤2.WebSphere应用服务器中内存泄漏的探测工具3.Java虚拟机概要分析和详细垃圾回收4.TPV监视JVM的状况5.生成Heapdump文件6.内存泄漏的分析诊断工具-MDD4J7.小结参考资料本文介绍了如何在...

    Linux:Java应用随着持续运行一段时间后,内存可用率逐渐减少的乌龙事件排查过程

    机器上有其他进程也占内存,我想确定下是否是内存泄漏导致的,查清楚后也能对线上的应用运行情况有更好掌握,如果有内存泄漏查出原因进行解决,避免隐患的发生。 二、 排查过程 整体的排查步骤如下: Java的堆内存和...

    Mac版jvm性能调优工具+内存监控+系统性能分析+Java开发助手+三高性能分析必备+Jprofiler_12.0.4

    软件主要功能如下: (1)监控堆内存的占用情况和创建对象实例的数量,找出内存泄露的原因; (2)监控占用CPU较多的方法; (3)监控线程的阻塞和死亡; (4)监控GC的耗时;

    Android应用内存泄漏的定位、分析与解决策略

    对于不同的语言平台来说,进行标记回收内存的算法是不一样的,像Android(Java)则采用GC-Root的标记回收算法。...有了上面的内存回收的栗子,那么接下来就可以说说什么是内存泄漏了。从定义上讲,Android(J

    Tomcat内存溢出的三种情况及解决办法分析

    这种现象比较少见,也比较奇怪,主要是和jvm与系统内存的比例有关。 这种怪事是因为JVM已经被系统分配了大量的内存(比如1.5G),并且它至少要占用可用内存的一半。有人发现,在线程个数很多的情况下,你分配给JVM...

    JAVA性能瓶颈和漏洞检测.JProbe.Suite.v7.0.part2

    识别内存泄漏:通过易用的两步分析,跟踪运行时的内存增长; Memory Instance Calculator:计算内存泄露量; 智能化内存分析:通过Leak Doctor发现可能的内存泄露源; Aggregate Memory Footprint:理解对象创建...

    JAVA性能瓶颈和漏洞检测].JProbe.Suite.v7.0.part1

    识别内存泄漏:通过易用的两步分析,跟踪运行时的内存增长; Memory Instance Calculator:计算内存泄露量; 智能化内存分析:通过Leak Doctor发现可能的内存泄露源; Aggregate Memory Footprint:理解对象创建...

Global site tag (gtag.js) - Google Analytics