这是昨天看java的垃圾回收时 写的一个测试类。代码如下
没想到运行之后 成了无限循环了,一直不停,郁闷了。
看了多遍代码、加了一些打印语句,也没有看出个所以然。
所以想请大家帮忙看看  向大家请教了class gb {
   static boolean gcrun = false;
   static boolean f = false;
   static int created = 0;
   static int finalized = 0;
   int i;
   gb() {
 created++;
 System.out.println("now created:" + created);
 i = created;
 if(created == 47)
 System.out.println("created 47");
}
protected void finalize() {
   System.out.println("into finalize()");
   if(!gcrun) {
   gcrun = true;
   System.out.println("beginning to finalize after created chairs have been 
                               created");
   }
   if(i == 47) {
System.out.println("finalizing chair #47, setting flag to stop chair 
                                   creation");
this.f = true;
   }
   finalized++ ;
   if(finalized >= created){
System.out.println("all finalized finalized");
this.created=0;
this.finalized=0;
   }
   System.out.println("outof finalize()");
}
}
public class garbage {
public static void main (String[] args) {

    while(!gb.f){
    new gb();
    System.out.println("to take up space");
    }
    System.out.println("after all chairs have been created:n total created
                                = "+gb.created+", total finalized = "+gb.finalized);
    
    System.out.println("gc():");
    System.gc();
    System.out.println("runFinalization():");
    System.runFinalization();
   
    System.out.println("bye!");
    
}
}

解决方案 »

  1.   


    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;class gb {
    static boolean gcrun = false; static boolean f = false; static int created = 0; static int finalized = 0; int i; gb() {
    created++;
    System.out.println("now created:" + created);
    i = created;
    if (created == 47){
    System.out.println("created 47");
    }
    } protected void finalize() {
    System.out.println("into finalize()");
    if (!gcrun) {
    gcrun = true;
    System.out
    .println("beginning to finalize after created chairs have been created");
    }
    if (i == 47) {
    System.out
    .println("finalizing chair #47, setting flag to stop chair creation");
    this.f = true;
    }
    finalized++;
    if (finalized >= created) {
    System.out.println("all finalized finalized");
    this.created = 0;
    this.finalized = 0;
    }
    System.out.println("outof finalize()");
    }
    }public class garbage {
    public static void main(String[] args) throws InterruptedException, SQLException {
    while (!gb.f) {
    new gb();
    Thread.sleep(1000);
    System.out.println("to take up space");
    //你的垃圾回收应该放在循环里面,否则永远执行不到外面!
    //生成47个对象后,以后每次都建议JVM垃圾回收,直到f=true终止循环!
    if(gb.created>=47){
    System.runFinalization();
    //这里也只是建议回收,JVM不一定真的回收!
    System.gc();
    }
    }
    System.out
    .println("after all chairs have been created:n total created = "
    + gb.created + ", total finalized = " + gb.finalized); System.out.println("gc():");
    System.out.println("runFinalization():");
    System.out.println("bye!");
    Connection con=DriverManager.getConnection("");
    con.createStatement(); }
    }
      

  2.   

    没有意义啊
    GC的调用时间由JVM决定
    finalize()同样也是由JVM决定调用
    这个并不能作为析构函数来处理
      

  3.   

    Connection con=DriverManager.getConnection("");
    con.createStatement();
    抱歉,这2行去掉,不小心加上去了

      

  4.   

    问题在于你不能控制或者假设某个对象在什么时候被回收,这个也是垃圾回收中最重要的一点.
    对你的代码进行一下修改,你就能看出问题了,修改如下
        protected void finalize() {
            System.out.println("into finalize()" + i);
    这样,你就会发现,47号对象不一定会在你想像的时刻被回收.
      

  5.   

    effective java 上说 finalize() 是有害的,不必要的,呵呵.
      

  6.   

     Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的内存非法引用。  垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,因此需要开发人员做比较深入的了解。  2.触发主GC(Garbage Collector)的条件  JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:  ①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。  ②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报“out of memory”的错误,Java应用将停止。  由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。  3.减少GC开销的措施  根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:  (1)不要显式调用System.gc()  此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。  (2)尽量减少临时对象的使用  临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。  (3)对象不用时最好显式置为Null  一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。  (4)尽量使用StringBuffer,而不用String来累加字符串(详见blog另一篇文章Java中String与StringBuffer)  由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。  (5)能用基本类型如Int,Long,就不用Integer,Long对象  基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。  (6)尽量少用静态对象变量  静态变量属于全局变量,不会被GC回收,它们会一直占用内存。  (7)分散对象创建或删除的时间  集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。
      

  7.   

    5.Java 内存泄漏  由于采用了垃圾回收机制,任何不可达对象(对象不再被引用)都可以由垃圾收集线程回收。因此通常说的Java 内存泄漏其实是指无意识的、非故意的对象引用,或者无意识的对象保持。无意识的对象引用是指代码的开发人员本来已经对对象使用完毕,却因为编码的错误而意外地保存了对该对象的引用(这个引用的存在并不是编码人员的主观意愿),从而使得该对象一直无法被垃圾回收器回收掉,这种本来以为可以释放掉的却最终未能被释放的空间可以认为是被“泄漏了”。  考虑下面的程序,在ObjStack类中,使用push和pop方法来管理堆栈中的对象。两个方法中的索引(index)用于指示堆栈中下一个可用位置。push方法存储对新对象的引用并增加索引值,而pop方法减小索引值并返回堆栈最上面的元素。在main方法中,创建了容量为64的栈,并64次调用push方法向它添加对象,此时index的值为64,随后又32次调用pop方法,则index的值变为32,出栈意味着在堆栈中的空间应该被收集。但事实上,pop方法只是减小了索引值,堆栈仍然保持着对那些对象的引用。故32个无用对象不会被GC回收,造成了内存渗漏。   以下是引用片段:public class ObjStack { 
      private Object[] stack; 
      private int index; 
      ObjStack(int indexcount) { 
      stack = new Object[indexcount]; 
      index = 0; 
      } 
      public void push(Object obj) { 
      stack[index] = obj; 
      index++; 
      } 
      public Object pop() { 
      index--; 
      return stack[index]; 
      } 
      } 
      public class Pushpop { 
      public static void main(String[] args) { 
      int i = 0; 
      Object tempobj; 
      ObjStack stack1 = new ObjStack(64);//new一个ObjStack对象,并调用有参构造函数。分配stack Obj数组的空间大小为64,可以存64个对象,从0开始存储。 
      while (i < 64) 
      { 
      tempobj = new Object();//循环new Obj对象,把每次循环的对象一一存放在stack Obj数组中。 
      stack1.push(tempobj); 
      i++; 
      System.out.println("第" + i + "次进栈" + "\t"); 
      } 
      while (i > 32) 
      { 
      tempobj = stack1.pop();//这里造成了空间的浪费。 
      //正确的pop方法可改成如下所指示,当引用被返回后,堆栈删除对他们的引用,因此垃圾收集器在以后可以回收他们。 
      /* 
      * public Object pop() {index - -;Object temp = stack [index];stack [index]=null;return temp;} 
      */ 
      i--; 
      System.out.println("第" + (64 - i) + "次出栈" + "\t"); 
      } 
      } 
      } 以上转自http://www.programfan.com
      

  8.   

    我昨天想的好像不对
    created 和finalized 是类属性,做计数器用的,不会是单独去标识一个对象的
    我是想生成47个之后就要回收的
      

  9.   

    死循环的话 改变一下判断条件就可以跳出循环了
    至于虚拟机什么时候回收垃圾 不是我们可以控制的 
    我们只能建议 是否真的回收了 那是虚拟机的事了只像跳出死循环的话 可以加一个计时器import java.util.Timer;
    import java.util.TimerTask;class gb {
    static boolean gcrun = false; static boolean f = false; static int created = 0; static int finalized = 0; int i; gb() {
    created++;
    System.out.println("now created:" + created);
    i = created;
    if (created == 47)
    System.out.println("created 47");
    } protected void finalize() {
    System.out.println("into finalize()");
    if (!gcrun) {
    gcrun = true;
    System.out
    .println("beginning to finalize after created chairs have been created");
    }
    if (i == 47) {
    System.out
    .println("finalizing chair #47, setting flag to stop chair creation");
    this.f = true;
    }
    finalized++;
    if (finalized >= created) {
    System.out.println("all finalized finalized");
    this.created = 0;
    this.finalized = 0;
    }
    System.out.println("outof finalize()");
    }
    }class garbage {
    public static void main(String[] args) {
    //定时...1分钟
    new ExecuteTimer(1).start();

    while (!gb.f) {
    new gb();
    System.out.println("to take up space");
    }
    System.out
    .println("after all chairs have been created:n total created = "
    + gb.created + ", total finalized = " + gb.finalized); System.out.println("gc():");
    System.gc();
    System.out.println("runFinalization():");
    System.runFinalization(); System.out.println("bye!"); }
    }
    //定时器 以分钟为单位
    class ExecuteTimer { 
        private final Timer timer = new Timer(); 
        private final int minutes;     public ExecuteTimer(int minutes) { 
            this.minutes = minutes; 
        }     public void start() { 
            timer.schedule(new TimerTask() { 
                public void run() { 
                 stopProgram(); 
                    timer.cancel(); 
                } 
                private void stopProgram() { 
                    gb.f = true;
                } 
            }, minutes * 60 * 1000); 
        }
    }