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

因此,在介绍过设计模式这一类外功之后,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 吧(语法都是浮云)。

http://www.cnblogs.com/zuoxiaolong

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

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

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

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

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

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

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

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

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

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

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

  6. JVM内存管理(二)

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

  7. 现代JVM内存管理方法的发展历程,GC的实现及相关设计概述(转)

    JVM区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园).Survivor Space(幸存者区).Tenured Gen(老年代-养老区). 非heap区又分: ...

  8. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  9. java虚拟机学习-JVM内存管理:深入Java内存区域与OOM(3)

    概述 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又 ...

随机推荐

  1. FreeMarker初探--安装FreeMarker

    这里安装FreeMarker相当简单,不需要真正的安装过程.仅仅是拷贝 lib/freemarker.jar 到你 Java 应用程序的路径中,让类加载器可以发现它.比如,如果你在 Web 使用了 F ...

  2. laravel中新建文件并保存数据到文件中

    //base_path()获取当前的绝对路径 $path=base_path().'\config\web.php'; $str='abcdefg'; //要声明的字符串 file_put_conte ...

  3. Qt界面(控件)相关设计

    (转自:http://blog.chinaunix.net/uid-25799257-id-600157.html) 引言  最近在做数据库相关课程设计,所以就借此机会,先熟悉一下Qt的一些编程,同时 ...

  4. 微信小程序单个倒计时效果

    var end_time = grouponList.expire_time.replace(/-/g, '/') grouponcountdown(that, end_time) //适用于商品列表 ...

  5. 利用国内镜像下载Android源码,并编译生成image镜像文件

    为了编译安卓源码,首先需要一个Linux,本次采用Ubuntu Kylin14.04,内核版本3.13.装在四核.4G内存.1T硬盘的虚拟机上查看内核版本号:$uname -all清华镜像地址清华镜像 ...

  6. 2017.10.23 Arduino Atmel EFM32低功耗监测

    mark:因为最近一直调试(维护)客户的EFM32,和其他系列的Atmel芯片.对atmel不熟悉,做点功课. 1. 自建Arduino 最小系统(原来树莓派都是Atmel的芯片) http://ww ...

  7. SDKMAN 软件开发工具包管理器

    SDKMAN 是用来在类Unix 系统中管理多个版本的开发环境的工具.提供命令行接口来安装.切换.删除.列出候选版本. SDKMAN!是在大多数基于Unix的系统上管理多个软件开发套件的并行版本的工具 ...

  8. kmeans实现文本聚类

    需求 拿到的需求是输入n个文本,对文本进行聚类,由于这些输入不能通过历史数据进行训练,所以这个主要就是用无监督学习来解决. kmeans 谈到聚类就会想到kmeans,它的核心思想是给定的K值和K个初 ...

  9. Azure 软件架构选择

    1. 传统的分层结构+message broker + worker传统的层结构老生常谈了: UI 层,service,业务逻辑,数据层.就不赘述了与worker形成producer-consumer ...

  10. linux给一个文件夹开启权限

    假如要给一个叫做xiaobang的文件夹权限,CD到这一级目录 chmod -R 777 xiaobang