文档章节

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

We911
 We911
发布于 2017/02/08 10:14
字数 1111
阅读 7
收藏 0

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

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

本文转载自:http://blog.csdn.net/liduanw/article/details/8192309

共有 人打赏支持
We911
粉丝 2
博文 63
码字总数 0
作品 0
深圳
程序员
私信 提问
用C#.NET调用Java开发的WebService传递int,double问题,出现java无法获

用C#.NET调用Java开发的WebService传递int,double问题,出现java无法获得值! 用C#.NET调用Java开发的WebService时,先在客户端封装的带有int属性的对象,当将该对象传到服务器端时,服务器端...

刘光强
2015/10/15
0
0
为 Java 开发者解读 Groovy 编程风格和语言特性

当一个Java开发人员加入到Groovy的开发之旅的时候,他/她经常带着Java思想去思考,并逐步地学习Groovy,每次学习一个特性,这会让他慢慢变得更有创造性和写出更符合语言习惯的Groovy代码。这...

oschina
2013/01/14
5.9K
18
第3章 Kotlin 可空类型与类型系统

第3章 Kotlin 可空类型与类型系统 跟Java、C和C ++ 一样, Kotlin也是“静态类型编程语言”。 通常,编程语言中的类型系统中定义了 如何将数值和表达式归为不同的类型 如何操作这些类型 这些...

程序员诗人
2017/09/25
0
0
JDBC 获取 Oracle 数据库连接(使用 Driver)

获取数据库连接的方法: 1. Driver 接口: •Java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现 •在程序中不需要...

passionfly
2014/11/17
0
0
scala语言与java的区别

scala支持关联映射,如可以用(key -> value)表示一个键值对 scala中的所有类型都是对象,包括基本数据类型 scala中的case语句用来判断接收的消息,比java中的switch...case...更专注 receiv...

jhonephone
2014/09/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Android安全防护防护———加密算法

摘要 这篇文章本来早就应该写了,但是由于项目一直开发新的需求,就拖后了。现在有时间了,必须得写了。现在Android应用程序对安全防范这方面要求越来越高了。特别是金融行业,如果金融app没...

北辰丨丶
27分钟前
1
0
MongoDB ObjectId详解及使用

MongoDB ObjectId详解及使用 2017年09月13日 14:25:18 universsky2015 阅读数:11802 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/universsky2015/article...

linjin200
31分钟前
2
0
Caffe在CentOS和Ubuntu上安装

1 CentOS上安装中需要配置第三方源 #sudo yum install epel-release 如果不安装第三方软件源,很多依赖包都不能通过yum安装 Makefile blas = open 2 Unbuntu PYTHON_INCLUDES=/usr/local/li...

shengjuntu
33分钟前
1
0
一线 IT 公司开发转管理,我是怎么从 0 到 1 的?

在某一线互联网公司的任职生涯马上就要结束了,回想起来,从 16 年校招加入,到今年年初离职,在这快三年的时间里,公司在飞速地发展和变化,我也从一个刚入职场的初级后台开发成长为带着十来...

编辑部的故事
34分钟前
1
0
Hibernate 自动建表默认编码格式改为UTF-8

Hibernate 自动建表时报编码错误: Caused by: java.sql.SQLException: Incorrect string value: '\...' for column 'cust_name' at row 1 一般情况我们使用的mysql方言为:org.hibernate.d......

gwl_
36分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部