B产生一个当一次循环过后就释放一个不过退出for后,B就什么也没有了,A中还有一个引用变量

解决方案 »

  1.   

    A 在经过循环之后 hash 还指向一个有效的 Hashtable 对象。
    B 在经过循环之后 hash 不可访问
      

  2.   

    A; Hashtable h=null;
    for(int i=0;i<99999;i++)
    {
    h=new Hashtable();
    }
    B: for(int i=0;i<99999;i++)
    {
    Hashtable h=new Hashtable();
    }
    A的垃圾回收
    [GC 512K->123K(1984K), 0.2321493 secs]
    [GC 635K->123K(1984K), 0.0043567 secs]
    [GC 635K->123K(1984K), 0.0019620 secs]
    [GC 635K->123K(1984K), 0.0009283 secs]
    [GC 635K->123K(1984K), 0.0009401 secs]
    [GC 635K->123K(1984K), 0.0009001 secs]
    [GC 635K->123K(1984K), 0.0008929 secs]
    [GC 635K->123K(1984K), 0.0011881 secs]
    [GC 635K->123K(1984K), 0.0012488 secs]
    [GC 635K->123K(1984K), 0.0009311 secs]
    [GC 635K->123K(1984K), 0.0014379 secs]
    [GC 635K->123K(1984K), 0.0013139 secs]
    [GC 635K->123K(1984K), 0.0009208 secs]
    [GC 635K->123K(1984K), 0.0012451 secs]
    [GC 635K->123K(1984K), 0.0012611 secs]
    [GC 635K->123K(1984K), 0.0009451 secs]
    [GC 635K->123K(1984K), 0.0008811 secs]
    [GC 635K->123K(1984K), 0.0009415 secs]
    B的垃圾回收
    [GC 512K->123K(1984K), 0.0581672 secs]
    [GC 635K->123K(1984K), 0.0032968 secs]
    [GC 635K->123K(1984K), 0.0019746 secs]
    [GC 635K->123K(1984K), 0.0008568 secs]
    [GC 635K->123K(1984K), 0.0012655 secs]
    [GC 635K->123K(1984K), 0.0008169 secs]
    [GC 635K->123K(1984K), 0.0007096 secs]
    [GC 635K->123K(1984K), 0.0008225 secs]
    [GC 635K->123K(1984K), 0.0007093 secs]
    [GC 635K->123K(1984K), 0.0008445 secs]
    [GC 635K->123K(1984K), 0.0010032 secs]
    [GC 635K->123K(1984K), 0.0011549 secs]
    [GC 635K->123K(1984K), 0.0011183 secs]
    [GC 635K->123K(1984K), 0.0010328 secs]
    [GC 635K->123K(1984K), 0.0011996 secs]
    [GC 635K->123K(1984K), 0.0011035 secs]
    [GC 635K->123K(1984K), 0.0011907 secs]
    [GC 635K->123K(1984K), 0.0011228 secs]
    大伙儿比较一下就知道了
      

  3.   

    基本相同的。二者都是产生10个对象。而A则保持最后一个对象引用在方法体中,循环结束时除了最后一个对象被引用,其他9个对象都可以被回收;而B则所有对象都在FOR循环中,FOR循环结束时所有10个对象都可以回收。
      

  4.   

    我认为大多数情况尽可能用一个HashTable更好C:Hashtable hash = new HashTable;
    for (int i = 0; i < 10; i++) {
        .......
        HashTable.clear();
    }
      

  5.   

    更正上面:
      HashTable.clear();

      hash.clear();
      

  6.   

    B要好些。A每次循环所创建的对象是要在下一次循环创建对象时引用计数器才为0,才符合垃圾回收条件。也就是说,A每次循环创建的HashTable对象最早也要在下次循环创建对象时才会释放。而最后一次循环创建的对象,只要hash的作用域内,就始终保持引用计数为1,无法释放。B每次循环创建的对象在本次循环结束时因为其变量作用域结束,导致引用计数器结束,对象释放。也就是说B代码相当于
    for (int i = 0; i < 10; i++) {
        Hashtable hash = new Hashtable();
        ......
        hash = null;    //变量即将超出作用域
    }
    而且循环结束后,没有残存对象。对于A,最好把代码加一句:
    Hashtable hash = null;
    for (int i = 0; i < 10; i++) {
        hash = new HashTable();
        .......
    }
    hash = null;    //使最后一次循环产生的对象的引用计数器变为0,好让垃圾回收器回收。
      

  7.   

    我个人比较同意formalin(福尔马林)的说法,但是有一点,JAVA的垃圾回收机制并不是在出作用域时回收的.而是当系统资源紧张时才进行回收的.
      

  8.   

    b好。1 作用域小,可以避免一些编程错误。
    2 编译器应该不会为b产生10个局部变量,所以栈桢所占内存和a是一样的。
    3 至于垃圾回收,应该没有太大区别,因为a中的hash变量是一个局部变量,它即使在循环之后不置为null也没什么关系。
      

  9.   

    to hiswing() :呵呵,我是说超出作用域就符合回收条件,至于什么时候回收还是看虚拟机的了。一般比较紧张的资源,我会在引用计数为零后调用System.gc(),主动回收。to 0xCafeBabe(咖啡宝贝~) :如果A代码所处的函数很长,在循环之后又作了好多事,那hash这个局部变量就要等好久才能超出作用域了。
      

  10.   

    但有一点我始终不清楚.请各位指教!!
    A.
    (1)在内存中声明了一个Hashtable,但并没有为其分配内存空间.
    (2)在for中为其分配内存空间.(这里,每次分配的是同一块内存空间吗?)
    B.
    (1)在for中声明Hashtable并为其分配内存空间.(这里,每次为其声明和分配的内存空间是否是不同的?)
      

  11.   

    答:
    A 不是。所以如果垃圾回收没有执行,将有10块内存。B 是不同的。每一次new都会分配一块内存。
      

  12.   

    我同意B。
    因为 formalin(福尔马林) 讲的很明白了!!
      

  13.   

    还是看字节码清楚
    package csdn;import java.util.*;public class Test1{
    public void foo(){
    int i;
    Hashtable hash;
    for (i = 0; i < 10; i++) {
         hash = new Hashtable();    
    }
    }

    public void bar(){
    int i;
    for (i = 0; i < 10; i++) {
         Hashtable hash = new Hashtable();    
    }
    }
    }public class csdn.Test1 extends java.lang.Object{
    public csdn.Test1();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   returnpublic void foo();
      Code:
       0:   iconst_0
       1:   istore_1
       2:   iload_1
       3:   bipush  10
       5:   if_icmpge       22
       8:   new     #2; //class Hashtable
       11:  dup
       12:  invokespecial   #3; //Method java/util/Hashtable."<init>":()V
       15:  astore_2
       16:  iinc    1, 1
       19:  goto    2
       22:  returnpublic void bar();
      Code:
       0:   iconst_0
       1:   istore_1
       2:   iload_1
       3:   bipush  10
       5:   if_icmpge       22
       8:   new     #2; //class Hashtable
       11:  dup
       12:  invokespecial   #3; //Method java/util/Hashtable."<init>":()V
       15:  astore_2
       16:  iinc    1, 1
       19:  goto    2
       22:  return}
    foo,bar两个方法的字节码居然是一样的!!所以,bar中的局部变量hash所指向的内存即使在循环结束后依然不能被垃圾回收,进一步,我认为在一个方法内部如何定义局部变量(在某些块内部或者不在)都不会对垃圾收集产生影响,这些变量所指向的内存都只有在方法结束后才有可能被垃圾收集。把hash定义在循环内,只会对编译器有影响,比如你在循环外再使用hash变量,那编译器就会报错。如果你想要bar中的变量hash所指向的内存在循环之后能被垃圾收集,你必须这样写
             public void bar(){
    int i;
    for (i = 0; i < 10; i++) {
         Hashtable hash = new Hashtable();    
                      hash=null;
    }
    }
      

  14.   

    最后一句应该这样说:如果你想要bar中分配的最后一个Hashtable在循环之后能被垃圾收集,你必须这样写
    public void bar(){
    int i;
    for (i = 0; i < 10; i++) {
         Hashtable hash = new Hashtable();    
                      hash=null;
    }
    }
    或者你多判断一下
    public void bar(){
    int i;
    for (i = 0; i < 10; i++) {
         Hashtable hash = new Hashtable();    
                      if(i==9) hash=null;                  
    }
    }
      

  15.   

    同意楼上因为在java中拉回收机制是程序员无法精确控制的如果程序员希望回收内存,只能将对象赋值为空
      

  16.   

    想知道区别吗?看下面的代码:public class Test1{
    public void foo(){
    int i;
    Hashtable hash;
    for (i = 0; i < 10; i++) {
              hash = new Hashtable();    
    }
                      try {
                           Thread.sleep(24*60*60*1000);
                      } catch(Exception e) {}
    }

    public void bar(){
    int i;
    for (i = 0; i < 10; i++) {
              Hashtable hash = new Hashtable();    
    }
                      try {
                           Thread.sleep(24*60*60*1000);
                      } catch(Exception e) {} }
    }A代码的最后一个hashtable的内存要在24小时之后才回收,而B代码最后一个hashtable的内存在任何java虚拟机需要的时候都可以回收。
      

  17.   

    to sniperlei(静水深流) 如果程序员希望回收内存,将对象赋值为空也没用。引用计数为0后,什么时候回收是看虚拟机的算法。文档里说调用System.gc(),可以建议回收。在我的实践中,调用System.gc(),百分百能够立即回收。
      

  18.   

    to formalin(福尔马林):
    你的Test1中的foo和bar的字节码实际上是一样的,所以你所说的"A代码的最后一个hashtable的内存要在24小时之后才回收,而B代码最后一个hashtable的内存在任何java虚拟机需要的时候都可以回收。"其实是不对的,bar中最后一个hashtable也不可能立即回收,和foo的情况是一样的。
      

  19.   

    也许你是对的,如果这道题的答案真是这样:
    http://expert.csdn.net/Expert/TopicView1.asp?id=2798638这样的话垃圾回收机制就很令人迷惑了,引用计数为零后还需要什么额外的条件才能满足回收呢?另外问一下,如何查看字节码?
      

  20.   

    用javap察看字节码现在的jvm应该都不会用引用计数的垃圾回收算法了,引用计数算法不能解决循环引用的问题。
    最新的hotspot好像是用分代的方法,即对年轻对象采用拷贝算法,对老对象采用标记清除算法。
      

  21.   

    B is good 
    我人为 formalin(福尔马林) 讲的很对!
    你可以参考他的例子,用你自己的方法!!!