zoukankan      html  css  js  c++  java
  • 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的时间回收点问题不会像本文的问题那样明显。所以权当学习而也。

  • 相关阅读:
    hdu 5446 Unknown Treasure lucas和CRT
    Hdu 5444 Elven Postman dfs
    hdu 5443 The Water Problem 线段树
    hdu 5442 Favorite Donut 后缀数组
    hdu 5441 Travel 离线带权并查集
    hdu 5438 Ponds 拓扑排序
    hdu 5437 Alisha’s Party 优先队列
    HDU 5433 Xiao Ming climbing dp
    hdu 5432 Pyramid Split 二分
    Codeforces Round #319 (Div. 1) B. Invariance of Tree 构造
  • 原文地址:https://www.cnblogs.com/jcli/p/2154276.html
Copyright © 2011-2022 走看看