java中显式设置实例为null多余吗

java中显式设置实例为null多余吗

大家先看段代码:

复制代码
 1 //启动参数设置:-Xms20m -Xmx20m -XX:SurvivorRatio=8 -Xmn10m
2 public static void main(String[] args) {
3 @SuppressWarnings("unused")
4 byte[] b1,b2,b3,b4;
5 long start = System.currentTimeMillis();
6 int i = 1;
7 while(i++ < 1000){
8 b1 = new byte[1 * _1M];
9 b2 = new byte[4 * _1M];
10 b2 = null;//这行注释掉的话,运行时间会不会有很大的不同呢?
11 b2 = new byte[4 * _1M];
12 }
13 System.out.println(System.currentTimeMillis() - start);
14 }
复制代码

先把我本地测试的结果贴出来:

有 b2=null 没有 b2=null
5922 ms 14749 ms
6187 ms 15077 ms
6066 ms 16021 ms

--------------------------------------------------------------------------------------

从结果可以看出来,在显示调用引用为null时,运行相同的代码1000次,时间竟然相差两倍有余。为何?

我们先把上面代码改成只运行一次,并设置参数打印GC详细日志:

复制代码
1 //启动参数设置:-Xms20m -Xmx20m -XX:SurvivorRatio=8 -Xmn10m -XX:+PrintGCDetails
2 public static void main(String[] args) {
3 @SuppressWarnings("unused")
4 byte[] b1, b2, b3, b4;
5 b1 = new byte[1 * _1M];
6 b2 = new byte[4 * _1M];
7 b2 = null;//先不注释运行,再把这行注释掉运行一次,比较两次的GC日志
8 b2 = new byte[4 * _1M];
9 }
复制代码

GC日志如下:

结论:当显示设置实例为null时,GC后的内存容量和GC消耗的时间都是不同的。此时显示设置为null的话,GC后已占用的堆内存更小,消耗时间更短。

至于为什么为这样,其实上面的GC详细日志内存的使用比例已经能说明问题,对于不是很清楚jvm内存模型的同学来说,还是看得不太清楚,下面我用简单的图讲解原因:

先看下内存管理图(这张图截至阿里温少的PPT)

至于详细的各内存块的含义,大家可以在网上找资料。针对这文章中的示例代码运行参数(-Xms20m -Xmx20m -XX:SurvivorRatio=8 -Xmn10m)设置,将会这样分配内存:

Eden 8m
s0 1m
s1 1m
tenured 10m

我们来分别详细分析下上面两种情况下内存的详细分配:

第一种情况(不显示设置null时)

?
b1 = new  byte [ 1  * _1M];

当执行这条语句时在Eden区分配1m内存。

?
b2 = new  byte [ 4  * _1M];

当执行这语句时再往Eden区分配4m内存。

?
b2 = new  byte [ 4  * _1M];

当执行这条语句时,虚拟机想再从Eden区申请4m内存,发现不够了(8m - 1m - 4m = 3m),于是进行一次GC操作。由于Eden区的两个内存块(b1为1m,b2为4m)现在都还不是可回收对象,所以会复制到survivor区,但是survivor区才1m空间放不下,于是复制到Tenured区。然后将Eden区块全部清空回收,这样Eden区又有8m空间了,可以将刚才的b2 = new byte[4 * _1M]放到eden区。最终内存情况就是下面的:

第二种情况(显示设置null时)

?
b1 = new  byte [ 1  * _1M];

当执行这条语句时在Eden区分配1m内存。

?
b2 = new  byte [ 4  * _1M];

当执行这语句时再往Eden区分配4m内存。

?
b2 = null ;

将第二步分配的4m字节数组标志为无效对象(空引用,待回收)

?
b2 = new  byte [ 4  * _1M];

重新申请4m空间,发现不够了(8m - 1m - 4m = 3m),于是进行一次GC操作。此时发现在Eden区中,b1指向的1m的字节数组为有效对象,而别一个4m的字节数组为无效对象(b2=null)。如是将1m字节数组内存复制到Tenured区中(只复制b1指向的实例)。然后将Eden区块全部清空回收,这样Eden区又有8m空间了,可以将刚才的b2 = new byte[4 * _1M]放到eden区。最终内存情况就是下面的:

总结:

我写这篇文章并不是想说明代码要显示设置无用对象为null还是不要设置。因为我这里举的例子中vm参数设置有点偏激,只是为了更好的说明问题,在生产中决不会设置内存20M,然后一个对象还占几M的空间这样的比例。

在一般的情况下,内存1G,对象实例也很小时,这个GC的时间回收点问题不会像本文的问题那样明显。所以权当学习而也。

原创文章,转载请注明出处,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值