« 前一篇:在WinForm程序中嵌入ASP.NET
后一篇:IT十大名言 »

Inner Class和内存泄漏 @ 2/12/2004

学习类
发信人: kiwi (冬虫夏草), 信区: Java
标  题: Inner Class和内存泄漏
发信站: BBS 水木清华站 (Thu Jan 15 12:49:17 2004), 转信
 
这是我工作中解决内存泄漏的时候碰到的问题,昨天在这里问到过有关的问题,现在将自己的认识共享。
 
class C {
        public static Vector container = new Vector();

        private class D {
        }

        public void addD() {
                container.add(new D());
        }

        public static void main(String[] args) {
                while(true) {
                        C aC = new C();
                        aC.addD();
                        aC = null;
                        try {
                                Thread.sleep(10000);    //sleep 10 seconds to do GC with JProfiler
                                //Do GC, how many instances of C and D will leave in memory?
                        }catch(InterruptedException e) {
                        }
                }
        }
}
 
在上面的做GC的地方,每个循环后,无疑有一个D对象会增加,因为它被加入到静态的container中。那么C呢?C在做操作以后被置成null了,应该能够被GC释放吧?不是的!每次循环后内存中会增加一个C对象,它无法被释放。
注意D是C的Non-static Inner Class,一个非静态的Inner Class只能由这个类的某个非静态的方法创建,这个Inner Class是能够读写它的Outer Class的非私有数据的,这是因为Java编译器在编译Inner Class时在类的定义里“偷偷”增加了一个域this$0,它指向生成Inner Class的对象实例,所以在D里面有一个C的引用!这样D被静态的container所引用,C又被D引用,这样aC即使被置为null,如果D不被释放,aC也不会被释放,这就造成了Memory Leak。这种内存泄漏十分的隐蔽!
 
解决这类Memory Leak的方法就是将Inner Class定义成静态(static)的,这样即使D对象不被释放,C对象也会被释放掉,这样就防止了这类内存泄漏。在<<Think in Java 3rd>>的第8章中讲到了Inner Class,其中有一句话这样说:“If you don’t need a connection between the inner class object and the outer class object, then you can make the inner class static. ”当然,如果Inner Class需要读取Outer Class对象的数据时,就不能定义成static,那么就要注意这种潜在的问题,及时释放Inner Class对象。
 
以上试验使用的JDK版本为1.3.1_06,观察内存情况使用了工具JProfiler 2.2.1。

发信人: windring (Hate), 信区: Java
标  题: Re: Inner Class和内存泄漏
发信站: BBS 水木清华站 (Thu Jan 15 13:23:58 2004), 转信
 
java中的变量出了作用域自然会被gc回收。是否显示的设成null是纯粹的多此一举,规范并没有保证设成null的变量一定立即回收,或者10秒以后回收,或者比不设null的变量先回收,这只取决于gc的调度方法,不应该由程序员来控制,程序员也不用关心,程序里面根本不应该出现这样的,否则java也就不称之为java了。
 
至于内存泄漏,我所见的有两种
1. 长时间运行的程序不断的向container中插入对象而没有释放或者及时释放
2. 一些不同于内存的资源(connection,socket,context等)没有调用close来释放
 
1取决于程序算法的设计,要考虑周全,并时时监控模块中关键的container数据结构的状态
2必须在编码时确定把close放在finally块中
 
你所说的这个归于1

btw: JProfiler可以检测并自动修正这两种情况吗?这个对于维护一些错漏百出的已有程序简直太游泳了
发布于 2/12/2004 4:30:09 | 评论:0

看帖要回帖...

categories
archives
links
statistics
  • 网志数:1168
  • 评论数:2011