`
donsun
  • 浏览: 31370 次
  • 性别: 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内存分析-内存泄露问题.rar

    2. **识别泄漏对象**:通过分析快照,找到长时间存活且占用内存大的对象,这些可能是潜在的内存泄漏源。 3. **查找引用链**:分析引用链,理解为什么这些对象没有被GC回收,可能存在哪些强引用、软引用、弱引用或虚...

    如何解决Java内存泄漏

    Java内存泄漏是软件开发中一个常见的问题,它不仅会影响应用程序的性能,还可能导致系统崩溃。通过深入了解Java的内存管理机制,并借助于专业的工具如OptimizeIt,可以有效地检测和解决内存泄漏问题。此外,开发者还...

    Java加载dll,导致Java进程内存泄露

    如果DLL中分配了内存但未正确释放,或者Java和DLL之间对对象的引用处理不当,都可能导致内存泄露,使得Java进程的内存占用持续增长,影响系统性能。 描述中的“NULL”可能是博主在描述问题时的简化表示,通常在编程...

    java内存泄露、溢出检查方法和工具

    3. **分析内存泄漏**:MAT提供多种视图来帮助定位问题,其中饼状图是最直观的一种。通过查看" Dominator Tree "视图,可以看到内存消耗最大的对象和它们之间的引用关系。此外,"Leak Suspects"报告会自动分析可能的...

    java内存泄露定位与分析[整理].pdf

    Java内存泄露定位与分析是Java开发中的一项重要任务,尤其在企业级应用系统中,内存管理的优化直接关系到系统的稳定性和性能。当系统出现内存泄露时,可能导致应用程序响应变慢,甚至出现 Out Of Memory (OOM) 错误...

    java 内存泄露分析流程

    总的来说,Java内存泄露分析是一个涉及多方面知识的过程,需要结合理论和实践来有效定位和解决问题。通过对内存模型、垃圾收集机制的理解,以及利用各种工具和技巧,我们可以有效地预防和解决内存泄露,确保系统的...

    Java+内存分析工具+MAT

    总结起来,MAT作为一款强大的Java内存分析工具,具备了深度分析、自动化检测内存泄漏、直观的内存结构展示等功能,是Java开发者必备的调试利器。无论是排查生产环境的内存问题,还是在开发阶段优化代码,MAT都能提供...

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

    总结,Java系统中的内存泄漏测试和分析涉及多个方面,包括理解内存管理机制、识别泄漏原因、使用专业工具以及制定有效的解决方案。开发者应当养成良好的编程习惯,注重代码质量,以减少内存泄漏的发生。同时,利用...

    java内存泄漏问题追踪

    4. "java内存泄露专题研究和应用_石麟.docx"可能提供了更深入的研究和实际案例,包括如何识别特定类型的内存泄漏,以及针对不同场景下的解决方案。而"ha450.jar"可能是一个示例应用或者工具,用于演示内存泄漏问题...

    java避免内存泄露

    ### Java避免内存泄露的关键知识点 ...通过以上分析,我们可以了解到在Java中避免内存泄露的一些关键策略和技术要点。正确地管理资源和引用,不仅可以提升程序的健壮性,还能提高系统的整体性能。

    jProfiler7 java内存分析 linux版本

    - 内存分析是识别和解决Java应用程序中的内存泄漏、过度对象创建和内存消耗过高问题的关键步骤。 - jProfiler7提供了详细的内存分配和存活周期视图,帮助开发者定位内存占用大的对象和可能导致问题的代码片段。 2...

    内存泄漏分析工具mat

    MAT(Memory Analyzer Tool)是由Eclipse基金会开发的一款强大的Java内存分析工具,它专门用于检测和分析Java应用的内存泄漏问题。 MAT提供了多种功能来帮助开发者诊断和解决内存泄漏问题。首先,MAT可以生成详细的...

    android系统分析内存泄露测试

    这本书可能会涵盖内存管理的基础知识,如何使用系统提供的工具进行内存分析,以及如何解决各种类型的内存泄漏问题。通过学习这些内容,开发者不仅可以诊断和修复现有的内存泄漏,还能提升对Android系统底层运作的...

    Java内存泄露及内存无法回收解决方案

    Java内存管理是编程中至关重要的一个环节,尤其是对于大型、长时间运行的应用来说,内存泄漏和内存无法回收可能导致系统性能下降,甚至导致系统崩溃。本文将深入探讨Java内存泄露的原理,分析内存无法回收的原因,并...

    java使用JMAP定位代码内存泄漏在哪

    JMAP是Java自带的一个命令行工具,它提供了对Java堆内存的详细分析功能,可以帮助我们诊断内存泄漏。JMAP的主要功能包括: 1. **生成堆转储文件**:通过`jmap -dump:format=b,file=&lt;filename&gt; &lt;pid&gt;`命令,我们可以...

    Java内存泄露检测

    Java内存泄露检测是Java开发中一个关键的议题,因为它直接影响到程序的稳定性和资源效率。内存泄露是指程序中已分配的内存无法被正确地释放,从而导致系统资源的浪费和可能导致程序性能下降甚至崩溃。 首先,理解...

Global site tag (gtag.js) - Google Analytics