各位园友好,LZ是从某网站转战过来的博主,看到这里很多博主都称看友们为园友,LZ斗胆模仿一下,不过以前,LZ其实都是称看友们为猿友的。之前LZ在某网站已经写了一系列文章,已经全部复制到了园内的新博客,主要是设计模式的内容,各位有兴趣的也可以去翻看一下,其中有不少还是颇受之前猿友们喜爱的。

作为一个程序猿,修炼的过程就犹如玄幻小说中的主角,不仅需要练习各种武技,内气的修炼的一样重要。虽然武技可以迅速的提升主角的实力,但是在内气太差的情况下,根本发挥不出武技的十之一二。

因此,在介绍过设计模式这一类外功之后,LZ就直接转战内气修炼,和各位猿友探讨一下JVM的内容。

本来这一章应该是介绍与GC相关的内容,不过在此之前,LZ准备先和各位探讨一下一个编程的小技巧。当然,这个小技巧其实也是与GC密切相关的。

不知道各位猿友有没看过一些JAVA内存相关的文章,里面在罗列建议的时候,经常会写出这样一条建议。

第XX条、请在使用完对象之后,显示的将对象设置为null。

原话不一定如此,但意思是一样的。话里所描述的意思,就是说我们以后写代码应该这么写。

Object obj = new Object();
//to do something
obj = null;

这段代码有点C/C++的风格,obj=null代替了C/C++中的delete obj或者是free(obj),相当于在提示我们,就算有了GC,我们也要像没有GC一样,使用完对象就得将其赋为空值。

首先,LZ这里要说明的是,将obj赋为空值,与C/C++中的delete其实有着天壤之别,LZ之所以说它们代替了delete和free,仅仅是因为它们出现在代码中的位置类似而已。

obj=null只做了一件事,就是将obj这个引用变量与new Object()创造的实例的关联断开,实际上,实例所占用的内存空间依然没有释放。

在提出这个建议的时候,很多博主或者图书的作者(因为有不少博主估计也是从书上看的)的本意,是想尽快消除引用与实例的关联,从而诱发GC在进行垃圾回收时,将实例所占用的内存释放。在某些时候,这么做也是为了消除内存泄露。

LZ个人觉得,许多博主或者是图书作者,提出这个建议的初衷,主要是针对一些没有接触过GC原理以及内存管理的程序猿而建议的,因为在不明白相关知识的前提下,很容易掌握不好变量的作用域,从而导致不必要的内存浪费(个人觉得这个并不是主要目的,因为只要没有发生内存泄露,内存终究是要被GC释放的),甚至是内存泄露。

所以为了安全起见,有些高人们就提出了这么一个建议。

有鉴于此,LZ个人觉得,在各位掌握了相关知识之后,完全可以忽略这个建议,而且这么做明显会降低代码的清晰度以及增加编码的负担,然而所换来的好处,却只是为了避免那根本不一定存在的内存泄露。

这里解释一下为何在有些时候不将对象赋为空值会造成内存泄露,我们考虑下面一段代码。

import java.util.Arrays;

public class Stack {

    private static final int INIT_SIZE = 10;

    private Object[] datas;

    private int size;

    public Stack() {
super();
datas = new Object[INIT_SIZE];
} public void push(Object data){
if (size == datas.length) {
extend();
}
datas[size++] = data;
} public Object pop(){
if (size == 0) {
throw new IndexOutOfBoundsException("size is zero");
}
return datas[--size];
} private void extend(){
datas = Arrays.copyOf(datas, 2 * size + 1);
} }

这段代码是一个简单的长度可伸缩的栈实现,在你写一段测试代码去测试它的时候,会发现它毫无问题。但是不好意思,这里面就有一个明显的“内存泄露”,这就是因为一些对象或者说引用没有设置为空值所造成的。

如果你还没看出来,LZ稍微提示一下,各位就会意识到了。这段代码里面,数组里的对象只会无限增长,而不会随着栈中元素的弹出而减少,减小的仅仅是对外展示的栈的大小size。考虑一个极端的场景,假设你曾经往栈中放入了100万个对象,最后使用了99万9千9百9十9个,从外部看来,栈中还只剩一个可用对象了,但是我们的栈依然持有着100万个对象的引用。如果JVM可以活过来的话,想必一定会把你蹂躏到死的。

我们缺少的就是将对象赋为null值的那一步,所以pop方法应该改为下面的方式,而且各位可以去看一下ArrayList中remove方法的源码,也是类似的思路。

    public Object pop(){
if (size == 0) {
throw new IndexOutOfBoundsException("size is zero");
}
Object data = datas[--size];
datas[size] = null;
return data;
}

这个内存泄露是非常隐蔽的,而且实际使用当中不一定就能发现,因为随着Stack对象的回收,整个数组也会被回收,到时内存泄露就被掩盖了。

所以个人觉得上述的那个建议是完全没有必要的,就算遵从了上面的建议,如果对内存管理不熟悉的话,也不会想到上面这个代码中的问题。如果想彻底的避免内存泄露的发生,机械式的主动将对象赋为空值,并不是一个可以从根本上解决问题的办法。

真正能够解决问题的办法,就是掌握好GC的策略与原理,定义一个变量时多注意变量的作用域,如此才可以更好的避免内存泄露。

所以学好GC原理还是很有必要的,希望准备走JAVA之路的朋友,尤其是从培训机构出来的猿友们(此处没有鄙视培训机构出来的猿友们的意思,因为LZ本人也是半路出家,从培训机构走上编程之路的程序猿之一),一定不要只专注于各个框架的使用以及业务的深入,虽然这些事很有必要,但并不是全部。

follow me and go the memory world 吧(语法都是浮云)。

JVM内存管理------杂谈(借此也论一论obj=null)的更多相关文章

  1. JVM内存管理------垃圾搜集器参数精解

    本文是GC相关的最后一篇,这次LZ只是罗列一下hotspot JVM中垃圾搜集器相关的重点参数,以及各个参数的解释.废话不多说,这就开始. 垃圾搜集器文章传送门 JVM内存管理------JAVA语言 ...

  2. JVM内存管理之垃圾搜集器参数精解

    本文是GC相关的最后一篇,这次LZ只是罗列一下hotspot JVM中垃圾搜集器相关的重点参数,以及各个参数的解释.废话不多说,这就开始. 垃圾搜集器文章传送门 JVM内存管理------JAVA语言 ...

  3. JVM内存管理------GC算法精解(复制算法与标记/整理算法)

    本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此基础上演化而来的,究竟这两种算法优化了之前标记/清除算法的哪些问题呢? 复制算 ...

  4. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  5. JVM内存管理及垃圾回收

    一.JVM内存的构 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Progra ...

  6. JVM内存管理--GC算法详解

    标记/清除算法 首先,我们回想一下上一章提到的根搜索算法,它可以解决我们应该回收哪些对象的问题,但是它显然还不能承担垃圾搜集的重任,因为我们在程序(程序也就是指我们运行在JVM上的JAVA程序)运行期 ...

  7. JVM内存管理及垃圾回收【转】

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  8. JVM内存管理之GC算法精解(复制算法与标记/整理算法)

    本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此基础上演化而来的,究竟这两种算法优化了之前标记/清除算法的哪些问题呢? 复制算 ...

  9. JVM内存管理(二)

    JVM内存管理          JVM在执行java程序的过程中,会把内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖 ...

随机推荐

  1. Keepalived+MySQL双主架构

    l  架构准备 Node1 192.168.15.3 Node2 192.168.15.4 VIP 192.168.15.254 l  软件 MySQL 5.6 Keepalive yum insta ...

  2. Hadoop HDFS Basic JAVA API

      org.apache.hadoop.fs.FileSystem 是HDFS的文件系统抽象,在分布式系统中管理HDFS文件和目录.文件内容存储在由多个相同大小的块(如64M)构成的datanode节 ...

  3. bootstrap简单的过一遍

    注:.xxxx 表示类(class=xxxx) <h1>到<h6>均可使用.另外还提供了.h1到.h6的class .lead可以让段落突出显示 <small>  ...

  4. MMORPG大型游戏设计与开发(构架)

    游戏整体是以经典的武侠世界/天龙八部作为基本的一种设计模式,大致分为以下几个部分. 游戏的简单的一次处理流程如下,不过有些凌乱,还有待完善. 程序设计方面,服务器基本上分为数据处理.日志.网络等模块, ...

  5. Stanford机器学习笔记-9. 聚类(Clustering)

    9. Clustering Content 9. Clustering 9.1 Supervised Learning and Unsupervised Learning 9.2 K-means al ...

  6. 第二届中国移动互联网测试大会PPT

    第二届中国移动互联网测试大会PPT下载_360云盘 (提取密码:7799) 第二届中国移动互联网测试大会PPT下载_百度云盘 (提取密码: ws8m) 第二届中国移动互联网测试大会PPT下载_Goog ...

  7. AC日记——统计单词数 openjudge 1.12 5

    05:统计单词数 总时间限制:  1000ms 内存限制:  65536kB 描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次 ...

  8. JVM再了解了解

    转自 http://www.cnblogs.com/Coda/p/4331432.html 相信大家已经了解到Java具有跨平台的特性,可以“一次编译,到处运行”,在Windows下编写的程序,无需任 ...

  9. eclipse无法导入Android工程的现象与解决办法

    最近在新导入一个Android工程时遇见了已有工程无法导入的情况.具体的现象就是每次导入时的导入窗口很快消失,而在eclipse的package explorer中却没有增加新导入的工程文件夹,没有其 ...

  10. NSDate 哪些事

    .什么是时间戳? 时间戳是自 1970 年 1 月 1 日(00:00:00 GMT)至当前时间的总秒数. 2.NSDate,时间戳,NSString 之间的转换 //string 转 date + ...