再谈java的内存泄露

这两天看了一本老书《bitter java》,第一次系统地了解了所谓“反模式”。就书的内容来说已经过于陈旧,书中提到的magic servlet、复合jsp等等反模式已经是早就熟知的编程禁忌,而如web页面不能有太多元素这样的反模式也因为ajax的出现(异步加载)变的不是那么“反模式”了,其中又讲述了很多ejb的反模式,这些在轻量级框架流行的今天也早已经过时。不过书中有一个章节倒是挺有价值,讲述的是java的内存泄露问题,我认为是我目前读的关于这方面问题比较有价值的介绍。
    网上关于java内存泄露的资料都过于玄乎,其实java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。作者在书中提到了3个场景:
1。流失监听器问题,在awt、swing编程中,给组件添加了事件监听器,这些组件的生命周期如果很长的话,监听器对象将不能被正确回收。关于GUI编程我不是很熟悉,这一点存有疑问,因为显然你触发一个按钮的事件,当然是一直期待同样的行为发生,如果删除了监听器或者使用弱引用让JVM回收不符合业务逻辑和用户体验。

2。集合类,集合类仅仅有添加元素的方法,而没有相应的删除机制,导致内存被占用。这一点其实也不明确,这个集合类如果仅仅是局部变量,根本不会造成内存泄露,在方法栈退出后就没有引用了会被jvm正常回收。而如果这个集合类是全局性的变量(比如类中的静态属性,全局性的map等),那么没有相应的删除机制,很可能导致集合所占用的内存只增不减,因此提供这样的删除机制或者定期清除策略非常必要。

3。单例模式。不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露,考虑下面的例子:
class A{
    public A(){
           B.getInstance().setA(this);
   }
   ....
}
//B类采用单例模式
class B{
     private A a;
     private static B instance=new B();
     public B(){}
     public static B getInstance(){
         return instance;
    }
    public void setA(A a){
          this.a=a;
    }
   //getter...
}

显然B采用singleton模式,他持有一个A对象的引用,而这个A类的对象将不能被回收。想象下如果A是个比较大的对象或者集合类型会发生什么情况。

    上面所讲的这些也启发我们如何去查找内存泄露问题,第一选择当然是利用工具,比如jprofiler,第二就是在代码复审的时候关注长生命周期对象:全局性的集合、单例模式的使用、类的static变量等等。

文章转自庄周梦蝶  ,原文发布时间 2007-11-11

时间: 2024-12-04 23:59:54

再谈java的内存泄露的相关文章

java造成内存泄露原因

一.Java内存回收机制 不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址.Java中对象是采用new或者反射的方法创建的,这些对象的创建都是在堆(Heap)中分配的,所有对象的回收都是由Java虚拟机通过垃圾回收机制完成的.GC为了能够正确释放对象,会监控每个对象的运行状况,对他们的申请.引用.被引用.赋值等状况进行监控,Java会使用有向图的方法进行管理内存,实时监控对象是否可以达到,如果不可到达,则就将其回收,这样也可以消除引用循环的问题.在J

再再谈java乱码:GBK和UTF-8互转尾部乱码问题分析(续)

GBK字节码用UTF-8解码 UTF-8 的编码规则 转码实例 解决问题 jdk 18 测试 jdk 1617 jdk 版本的影响 小结 参考 在<再谈java乱码:GBK和UTF-8互转尾部乱码问题分析>我们分析了,如果从一个UTF-8 的字节序列,经过 new String(b,"GBK") 的操作,"可能"(与总字节数有关)会破坏数据.结果可能是,损失最后一个"字". 反过来呢?可能会很惨,大范围溃散... 同时,可参考:一段j

java web 内存泄露问题

问题描述 java web 内存泄露问题 在做web项目,需要从数据库一次读取多个数据,然后填充到bean里放入list,这样在循环读取的时候每次都要创建一个bean对象,之前访问量小没什么,现在访问量大了,程序占用越来越高,这应该怎么办? 解决方案 看下有没有对象在持续引用bean对象,特别是静态成员.把jvm的内存调大 解决方案二: Java的一个重要优点就是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存.因此,很多程序员认

JS魔法堂:再识IE的内存泄露

一.前言   IE6~8除了不遵守W3C标准和各种诡异外,我想最让人诟病的应该是内存泄露的问题了.这阵子趁项目技术调研的机会好好的再认识一回,以下内容若有纰漏请大家指正,谢谢!   目录一大坨!     二.内存泄漏到底是哪里漏了?        2.1. JS Engine Object.DOM Element 和 BOM Element        2.2. JS Engine Object的内存回收机制        2.3. DOM Element的内存回收机制        2.4.

测试Java Applet内存泄露(非开发环境)

问题描述 我有一个VB.NET开发的桌面程序,里面调用了IE浏览器控件,连接到一个URL,这个URL包含有一个JavaApplet.现在怀疑这个Java小程序有内存泄露的问题,最后导致我的程序运行越来越慢,直到崩溃.但是这个JavaApplet并不是我们开发的,而是国外制造的一个小设备产生的(这个小设备只有一根网线接口,不能接鼠标键盘控制,只知道里面运行了Linux).我如何收集数据,证明这个JavaApplet的对或错呢?我先使用了JProbe和YourKitJavaProfiler,发现它们

(6)java的内存泄露问题

一:什么是内存泄露--->Java的一个最显著的优势是内存管理.你只需要简单的创建对象而不需要负责释放空间,因为Java的垃圾回收器会负责内存的回收.然而,情况并不是这样简单,内存泄露还是经常会在Java应用程序中出现--->内存泄露的定义:对于应用程序来说,当对象已经不再被使用,但是Java的垃圾回收器不能回收它们的时候,就产生了内存泄露.要理解这个定义,我们需要理解对象在内存中的状态.如下图所示,展示了哪些对象是无用对象,哪些是未被引用的对象: ---->上图中包含了未引用对象和引用

再谈java乱码:GBK和UTF-8互转尾部乱码问题分析

一直以为java中任意unicode字符串可以使用任意字符集转为byte[]再转回来只要不抛出异常就不会丢失数据事实证明这是错的. 经过这个实例也明白了为什么 getBytes()需要捕获异常虽然有时候它也没有捕获到异常. 言归正传先看一个实例. 用ISO-8859-1中转UTF-8数据 设想一个场景 用户A有一个UTF-8编码的字节流通过一个接口传递给用户B 用户B并不知道是什么字符集他用ISO-8859-1来接收保存 在一定的处理流程处理后把这个字节流交给用户C或者交还给用户A他们都知道这是

再谈java回调函数_java

又遇到了回调函数,这次打算写下来分享一下. 所谓回调函数,或者在面向对象语言里叫回调方法,简单点讲,就是回头在某个时间(事件发生)被调用的函数. 再详细点:就是一个函数A,作为参数,传入了另一个函数B,然后被B在某个时间调用. 这里可以有疑问了,既然是一个函数调用另一个函数,可以在函数体里面调用啊,为什么还要把函数作为参数传到另一个函数里被调用?何况还有一些语言(比如java)不支持把函数作为参数. 对的,确实可以在函数体里调用另一个函数,功能上好像是没差别的,但是这里有一个问题,就是你要调用的

JAVA程序内存泄露问题

问题描述 使用quartz每20秒执行一次任务,任务中使用kettle做了一系列的数据抽取转换.程序跑了12个小时后内存从100上升到400.使用jmap导出内存查看后发现内存增长后组要是Unreachableobjects占用在增长.以下是Unreachableobjects的明细图:请问又没有朋友遇到过这样的情况,或者有什么排查的好办法? 解决方案 解决方案二:等待学习--解决方案三:quartz的线程初始化是10个,看下线程是不是一直在增加解决方案四:该回复于2011-03-25 13:2