之前看了个帖子:http://topic.csdn.net/u/20100607/11/1c78424d-c384-4d81-a87d-011704a37ff1.html#replyachor
说“调用 System.gc()有可能不会立即使 GC 进行内存回收”。然后就 Google 了下,大多也都这么说。
所以想做个测试,最初想通过 Runtime 获取 JVM 的内存使用情况来验证。可是这个方步行不通。因为 Runtime 所获取的内存使用情况很让人困惑。例如:
public static void main(String[] args) throws Exception {
Runtime runtime = Runtime.getRuntime();
System.out.println("runtime.totalMemory()->"+runtime.totalMemory());
System.out.println(runtime.freeMemory()); // sign_1
List<Object> list = new ArrayList<Object>();
for(int i = 0;i<10;i++){
list.add(new Test(i));
}
System.out.println("runtime.totalMemory()->"+runtime.totalMemory());
System.out.println(runtime.freeMemory()); //sign_2
}
sign_1 和 sign_2 的输出竟然一致。不晓得为什么。能否有明白人给指指。谢了。这条路不通我便想到了 finalize 放法。于是写了下面的代码:public class Test {

int i ;
static int j;

public Test() {
}

public Test(int i) {
this.i = i;
}

public static void main(String[] args) throws Exception {
System.gc();
List<Object> list = new ArrayList<Object>();
for(int i = 0;i<10;i++){
list.add(new Test(i));
}
list = null;

System.gc();

Thread.sleep(1000);
System.out.println("******************"+j);
}

@Override
protected void finalize() throws Throwable {
j++;
System.out.println("Over"+i+"->"+this.hashCode());
super.finalize();
}}上面的代码中,为什么向 list 中添加任意数目的 Test (大于等于1个),在 list = null;后调用 System.gc(); 都会导致  finalize() 的执行。当然,据说此时 JVM 也会在下次 GC 活动时,才会真正的对该对象所占用的内存进行回收。(Think In Java 中这么说的,所以姑且信吧)。可是谁又能证明:在没有 finalize 方法的情况下, 调用 System.gc()后,如果JVM 中的内存占用不严重, GC 不会立即进行内存回收。望不吝赐教。

解决方案 »

  1.   

    System.gc()后,如果JVM 中的内存占用不严重, GC 不会立即进行内存回收
    谁也没这么说过啊 !!
    System.gc()后jdk会根据自己的算法去计算是否要去垃圾回收,且不同的jdk实现不一样,IBM的jdk没准就和sun的不同
      

  2.   


    嗯~~~那能否通过测试,来验证 System.gc() 被调用后,GC 没有工作呢。也许没有意义,但是,只有被证明后才死心。谢谢了。还有一个问题:
      

  3.   

    显示调用System.gc();(该方法不保证立即会执行,因为不同的JVM使用不用算法来管理GC)。
    1、finalize()的执行时间不确定,具体根据不同版本的JVM和不同垃圾回收策略有关 
    2、finalize()中抛出的任何异常都将被忽略 Effective JAVA 中介绍finalize()的作用有两个 
    1、作为释放资源的安全网,在JDK,OutputStream等流中,如果使用者万一忘了关闭流,finalize()还可以最终得到一次关闭的机会(注意,不要指望靠它关,它只能作为一种备用策略)。 
    2、JNI调用的外部资源,在JAVA里没有直接关闭的代码,写在finalize()中。 子类一旦复写了finalize(),必须super.finalize(),否则父类的finalize()不执行。 
    1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候. 
    2.程序退出时为每个对象调用一次finalize方法。 
    3.显式的调用finalize方法 除此以外,正常情况下,当某个对象被系统收集为无用信息的时候,finalize()将被自动调用,但是jvm不保证finalize()一定被调用,也就是说,finalize()的调用是不确定的,这也就是为什么sun不提倡使用finalize()的原因. 
      

  4.   

    首先,就不同的jvm版本来说,可能垃圾回收机制不同,就1.6而言,GC调优的参数很多,如-XX:-UseConcMarkSwee
    pGC -XX:-UseParallelGC -XX:-UseParallelOldGC -XX:-UseSerialGC . 不同的状态GC工作情况肯定不同.
    其次,在 list = null;后调用 System.gc();只能说明的你代码里的finalize()方法被执行而super.finalize()中,虚拟机去没去做垃圾回收不好说,只能指定版本,然后去查看native代码.
      

  5.   

    不太清楚这个原理。
    不过看过的资料都说。在手动调用System.gc();后。会由JVM自己判断进不进行内存回收。
      

  6.   

    GC 通常它的线程优先级很低(应该是最低--我不是很清楚)。
    下面可以利用 finalize 至少可以保证运行一次来证明:在通常情况下(内存足够),GC并不会马上对内存进行回收,而是等到 所有其他高优先级的线程都已经运行结束。
    public class Test implements Runnable{
     public static void main(String args[]){
     Test test = new Test();
     Test1 test1 = new Test1();
     test.run();
     test1 =null;
     System.gc(); } @Override
    public void run() {
    // TODO Auto-generated method stub
    try{
    for(int i=0;i<10;i++){

    Thread.sleep(1000);

    System.out.println(i);
    }

    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }


    }
    }class Test1 { @Override
    protected void finalize() throws Throwable {
    // TODO Auto-generated method stub
    System.out.println("我将被回收!");
    super.finalize();
    }

    }
      

  7.   


    感谢朋友的回复!但是我是想证明:调用 System.gc 后 GC 没有运行。如何才能验证这种情况呢
      

  8.   

    本来昨天想做个测试来证明一下,调用GC后 并不马上运行,但是效果并不理想。
    我本来的思路是,用两个线程,一个高优先级线程不停的打印数据,在一定的时候sleep一段时间。另一个线程首先创建一个对象,然后调用system.gc ,我预想的结果是等到高优先级线程休眠的时候 gc 才会运行(证明运行我还是只想到用 finalize方法,这个方法在GC对对象进行回收的时候必然会运行,这个可以肯定的吧,权威是这么说的--有的时候有的东西不好验证,姑且信一下书)。
    但是结果并不尽人意,我这个小菜鸟把问题想的太简单了,看来要测试这个问题还得做出一个比较复杂的环境。LZ加油研究。
      

  9.   

    GC比较复杂,jvm的代码是看不到的,有懂c又懂jvm的高手就好了。
      

  10.   


    10List这点内存。   想看出什么呀。
      

  11.   


    我想即时一个字节也应该能看出来。因为 free freeMemory() 精确到字节。除非这么看这个问题:
    “JVM 不会在每次内存有所消耗的时候都去‘同步 freeMemory() 所获取的那个值’。只有内存消耗到一定程度后,JVM 认为有必要去同步是,它才去修改 通过 freeMemory() 所获取的那个值”。但是我没有看到这方面的信息。如果真的是这样。那么也就是说,将不能通过 Runtime 来获得“准确的内存使用情况”。
      

  12.   

    这么个简单的程序虚拟机反应一样是很正常的。就像我运行c程序读取没有初始化的变量,很有可能都是同一块内存,但是到了下一次就不一定了。
    我想如果这是个很复杂的或者分布式的程序就不像现在看到的那样每次都是这种结果。具体实现可以去sun下载jvm源代码自己看看内存释放的算法。System.gc()是不推荐使用的,还是不要用的好,通常把一个对象设置为null了之后你就可以假设它即将被回收了
      

  13.   

    System.out.println("total memory = "+Runtime.getRuntime().totalMemory()+"\tnow memory = "+Runtime.getRuntime().freeMemory());就能看到了。。真是。。
      

  14.   

    如果只是为了验证“调用System.gc()后有可能不会立即使 GC 进行内存回收”的话,我写了个小的程序可以证明:
    class Garbage
    {
    int index;
       static int count;
      Garbage()
       {
          index=++count;
          System.out.println("Object "+count+"onstruct");
       }
    protected void finalize()
    {
    System.out.println("Object"+ index+"is reclaimed !");
    }
    }
    public class TestReclaim
    {
    public static void main(String [] args)
      {
        Garbage my = new Garbage();
         new Garbage();
         new Garbage();
         new Garbage();
         new Garbage();
         new Garbage();
         new Garbage();
         System.gc();
         my.finalize();
       }
    }在textpad中运行结果为:
    Object 1onstruct
    Object 2onstruct
    Object 3onstruct
    Object 4onstruct
    Object 5onstruct
    Object 6onstruct
    Object 7onstruct
    Object1is reclaimed !
    Object7is reclaimed !
    Object6is reclaimed !
    Object5is reclaimed !
    Object4is reclaimed !
    Object3is reclaimed !
    Object2is reclaimed !
    从这个程序中就能看出在调用了System.gc()后系统并没有立即进行垃圾回收