zoukankan      html  css  js  c++  java
  • java中将对象引用设置为null对于GC有没有帮助

         相信,网上很多java性能优化的帖子里都会有这么一条: 尽量把不使用的对象显式得置为null.这样有助于内存回收

         可以明确的说,这个观点是基本错误的.sun jdk远比我们想象中的机智.完全能判断出对象是否已经no ref..但是,我上面用的词是"基本".也就是说,有例外的情况.这里先把这个例外情况给提出来,后续我会一点点解释.这个例外的情况是, 方法前面中有定义大的对象,然后又跟着非常耗时的操作,且没有触发JIT编译..总结这句话,就是: 除非在一个方法中,定义了一个非常大的对象,并且在后面又跟着一段非常耗时的操作.并且,该方法没有满足JIT编译条件,否则显式得设置 obj = null是完全没有必要的

     上面这句话有点绕,但是,上面说的每一个条件都是有意义的.这些条件分别是

    1 同一个方法中
    2 定义了一个大对象(小对象没有意义)
    3 之后跟着一个非常耗时的操作.
    4 没有满足JIT编译条件

     上面4个条件缺一不可,把obj显式设置成null才是有意义的. 下面我会一一解释上面的这些条件

    同一个方法中

     这个条件是最容易理解的,如果大对象定义在其他方法中,那么是不需要设置成Null的,

     1 public class Test
     2 {
     3  
     4      public static void main(String[] args){
     5      
     6          foo();
     7          
     8          System.gc();
     9      }
    10     
    11      public static void foo(){
    12          byte[] placeholder = new byte[64*1024*1024];
    13     }
    14 }

     对应的输出如下,可以看到64M的内存已经被回收

    D:>java -verbose:gc Test
    [GC 66798K->66120K(120960K), 0.0012225 secs]
    [Full GC 66120K->481K(120960K), 0.0059647 secs]

     其实很好理解,placeholder是foo方法的局部变量,在main方法中调用的时候,其实foo方法对应的栈帧已经结束.那么placeholder指向的大对象自然被gc的时候回收了.

    定义了一个大对象

    这句话的意思也很好理解.只有定义的是大的对象,我们才需要关心他尽快被回收.如果你只是定义了一个 Integer i = new Integer(1); 后续手动设置成null让gc回收是没有任何意义的.

    后面跟着一个非常耗时的操作

    这里理解是:后面的这个耗时的可能超过了一个GC的周期.例如

    1 public static void main(String[] args) throws Exception{
    2          byte[] placeholder = new byte[64*1024*1024];
    3          Thread.sleep(3000l);
    4          // dosomething
    5 }

     在线程sleep的三秒内,可能jvm已经进行了好几次ygc.但是由于placeholder一直持有这个大对象,所以造成这个64M的大对象一直无法被回收,甚至有可能造成了满足进入old 区的条件.这个时候,在sleep之前,显式得把placeholder设置成Null是有意义的. 但是,如果没有这个耗时的操作,main方法可以非常快速的执行结束,方法返回,同时也会销毁对应的栈帧.那么就是回到第一个条件,方法已经执行结束,在下一次gc的时候,自然就会把对应的"垃圾"给回收掉.

    没有满足JIT编译条件

      jit编译的触发条件,这里就不多阐述了.对应的测试代码和前面一样

    1 public class Test
    2 {
    3     public static void main(String[] args) throws Exception{
    4         byte[] placeholder = new byte[64*1024*1024];
    5         placeholder = null;
    6         //do some  time-consuming operation
    7         System.gc();
    8     }
    9 }

     在解释执行中,我们认为placeholder = null;是有助于对这个大对象的回收的.在JIT编译下,JIT编译器进行控制流和数据流分析后,生成的OopMap就提供比较精确的信息,不需要通过”=null”来告知对象使命已经完成.退一步说,这时即使有”=null”操作,也会被优化掉,生成出来的本地代码与没有”=null”操作的版本是一模一样的.

    转自http://chenjingbo.iteye.com/blog/1980908

  • 相关阅读:
    最长有效括号
    C++ 环形缓存区的实现
    vector的原理与底层实现
    聚合分析与分组
    求两个数的最大公约数
    单例模式
    工厂方法模式
    责任链模式
    适配器模式
    策略模式
  • 原文地址:https://www.cnblogs.com/ouhaitao/p/9996374.html
Copyright © 2011-2022 走看看