要点:要为每一个图片资源声明一个对象变量
  假设在一个程序声明了2个图片对象:
      Image pic1,pic2;
  如果在某一时刻要使用pic1和pic2则:
      if(pic1==null)pic1=Image.createImage("/1.png");
      if(pic2==null)pic2=Image.createImage("/2.png");
  当这些图片用完后,就应当:
      pic1=null;
      pic2=null;
  如果需要使用另外两个图片3.png和4.png,则最好另声明两个变量对象pic3,pic4来导入它们,不要使用pic1,pic2变量来导入这两个图片,如:
      if(pic1==null)pic1=Image.createImage("/3.png");//不要这样做,为什么不要这样做
      if(pic2==null)pic2=Image.createImage("/4.png");//不要这样做,为什么不要这样做
  因为这样做会影响垃圾收集器对pic1,pic2对象的回收工作,从而造成内存回收不干净,为什么会不干净

解决方案 »

  1.   

    LZ研究好深入,不知LZ看的哪本书,我也去学习下.
      

  2.   

    〉因为这样做会影响垃圾收集器对pic1,pic2对象的回收工作,从而造成内存回收不干净lz要明白,垃圾回收的对象是堆内存
    Image pic1,pic2;
    你pic1,pic2是放在栈内存里的
    所以,pic1,pic2不属于回收的对象
      

  3.   

    当这些图片用完后,就应当: 
          pic1=null; 
          pic2=null; 
      如果需要使用另外两个图片3.png和4.png,则最好另声明两个变量对象pic3,pic4来导入它们,不要使用pic1,pic2变量来导入这两个图片,如: 
          if(pic1==null)pic1=Image.createImage("/3.png");//不要这样做,为什么不要这样做 
          if(pic2==null)pic2=Image.createImage("/4.png");//不要这样做,为什么不要这样做 
    我认为这段话的观点有问题.
    用新的pic3,pic4倒是不给垃圾回收添加麻烦,但pic1和pic2指向听对象没有用了,还占着内存,确会给你的程序带来麻烦。相较而言,还是把pic1,pic2设为null,再让它们指向新的对象好一点吧。
      

  4.   

    据说老版本的JAVA对内存进行回收的方式是,当发现一块内存区域在程序中被对象引用的次数为0时,就进行回收。但是这样做可能会产生一些问题,比如用户不希望释放的空间被垃圾收集器自行释放。因此后来对回收机制进行了修改,更加具体的细节我也不清楚了。如LZ所写的“不可这样做”,程序会丢失对pic1和pic2的引用,此时垃圾收集器不会自动回收这两块区域,成程序员又无法自行释放,这样就可能导致内存回收不干净。嗯,第二段是我猜测的。
      

  5.   

    那栈中的东西只会越来越多了?
    pic1现在指向了一个新的对象,不指向原来那个了,难道它不会回收原来那个对象吗
      

  6.   


    所以说
    当执行
    pic1=null; 
    pic2=null; 
    的时候,他们原本指向堆内存的那个对象会被回收
    而pic1,pic2不会
    所以,没有必要再弄个pic3,pic4出来
    直接再用pic1,pic2就好了
      

  7.   

    其实楼住的这本书写的还不错,能指出这个问题,但是作者并没有说明这个问题
    if(pic1==null)pic1=Image.createImage("/3.png");//不要这样做,为什么不要这样做 
    if(pic2==null)pic2=Image.createImage("/4.png");//不要这样做,为什么不要这样做 
    为什么不要这样做呢,因为这样会导致内存泄露。
    pic1 =null pic2=null 指示JAVA虚拟机可以回收 pic1 和 pic2 在堆上申请的内存
    但是pic1 和 pic2 此时所指向的堆上的内存并没有释放,因为在等JAVA虚拟机空闲的时候再回收内存。 然而此时又重新在堆上申请内存然后赋值给 pic1 和pic2 。 现在问题就出现了。那么原来的那片申请的空间变成了一个野地址,即没有变量指向它了,所以JAVA虚拟机回收不了原来最早申请的内存了。
      

  8.   

    ThirstyCrow
    不是我扯蛋,事实就是这样。你自己不懂而已
    java的地层是C++做的,既然是C++ 做的就会在使用不当的时候
    有内存泄露,
    ThirstyCrow 不懂就不要乱否定别人的成果,如果你能写JNI ,能够直接
    用C++ 操作虚拟机并且能释放虚拟机的内存,能够自己做个内存泄露检测工具
    你就能解释楼住的这个问题
      

  9.   

    楼上的观点确实有问题啊.垃圾回收器,做的就是回收那些没有引用指向的对象,虽然它的工作方式不尽如人意,成为垃圾的对象,不能叫内存泄露,因为这此垃圾都记录在案了,都可以找得到。回到pic1,pic2的问题上,如果pic1,pic2指向的对象没有用了,还让pic1和pic2指着,对象占的内存永远也不可能释放,这和内存泄漏一样了。
      

  10.   

    不是这样的,即使你不让pic1=null;jvm也能确定在代码最后一次对pic1进行使用之后将它看做垃圾,编译器可以进行活性分析确定其生命周期的终结,并不需要你手工的设置null来告诉jvm。不会出现“对象占的内存永远不可能释放”这种问题。
    可以参考
    http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2906.pdf
    或者
    http://blog.csdn.net/axman/archive/2009/04/09/4058542.aspx
      

  11.   

    讨论变得越来越精彩
    学习ing
      

  12.   

    两个资料都看了,不过我对这种说法表示怀疑。否则如何解释下面这个实验的结果。(使用的是jdk1.6.0_13自带的jre)
    import java.io.IOException;public class Main {    public static void main(String[] args) throws IOException {        int[] arr1 = new int[Short.MAX_VALUE];
            int[] arr2 = new int[Short.MAX_VALUE];        System.out.println("Press any key to continue.");
            System.in.read();
            
            // 启动jvisualvm, 对本地的Main程序进行heap dump,
            // 查看所有int[]对象,你会看到两个大小为131084的        
            // 实例。这里所说的大小是只对象所占空间的大小,而
            // 不是数组的长度。用鼠标选择这两个对象,可以看到它
            // 们的长度为32767。
            
            arr2 = new int[0];
            System.out.println("Press any key to continue.");
            System.in.read();
            
            // 重新进行heap dump,这次只乘下一个大小为131084的
            // int[]对象。arr2最初指向的对象,已经可以被回收了,
            // 所以不再列出。
            printArray(arr1);        // 现在arr1使用完了,再次进行heap dump,还是能看到
            // 大小为131084的int[]对象。即使你点Monitor tab下
            // 的Perform GC强制回收,结果仍是如此。这说明arr1指
            // 向的int[]对象暂时是不能回收的。或者还有其它解释?
            // (比如说JDK自带的JRE没有启用JIT?)
            System.out.println("Press any key to continue.");
            System.in.read();
        }    public static void printArray(int[] arr) {
            return;
        }
    }
      

  13.   

    楼主看的什么垃圾书啊,会误人子弟的。Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环引用的问题),但执行效率很高。
      

  14.   

    楼上可以看我这个例子:public class Test{
    private String s1;
    public Test(String str){
    this.s1 = str;
    System.err.println("创建对象:"+s1);
    }
    public static void main(String[] args){
    Test t1 = new Test("t1");
    Test t2 = new Test("t2");

    for(int i = 0;i<100000;i++){
    }

    System.err.println("准备调用System.gc()!");
    System.gc();
    System.err.println("调用System.gc()之后!");
    System.err.println("让t1指向新的对象,内容为t3");
    t1 = new Test("t3");
    System.err.println("准备再次调用System.gc()!");
    System.gc();
    System.err.println("再次调用System.gc()之后!");

    }
    public void finalize(){
    System.err.println("Garbage collection!I'm "+s1);
    }
    }
    多运行几次,因为多次运行的结果可能不同。
    但起码有情况能说明,t2可能会在t3创建之前就回收了。上面链接中那个报告是gc 技术组给出的,估计可信性比较大。
      

  15.   

    1年没摸java了,全忘了,记号先
      

  16.   


    使用完了只是你自己的认为而已,但事实上arr1还指向原来那个对象
      

  17.   

    其实呢 java虚拟机是用C实现的,当然C++也能实现啦,只是符合虚拟机规范即可。
    不过你对java的内存回收机制似乎是不太了解,这个跟C++是不是使用恰当倒是没多大关系。
    至于那本书上说,不要那样使用,会造成回收不干净那完全是扯淡,如果那样回收不干净,你用其它方式同样回收不干净,其它方式能回收,那样也能回收。这取决与jvm实现,而且没有任何一个官方文档与java编程规范中说这样用不好,会回收不干净,如果那个虚拟机连这种回收都做不到,那么那个虚拟机不用也罢。