谈JAVA的内存回收

程序员需要通过关键字new创建Java对象,即可视为Java对象申请内存空间,JVM会在堆内存中为每个对象分配空间,当一个Java对象失去引用时,JVM的垃圾回收机制会自动清除他们,并回收它们所占用的内存空间。Java内存管理包括内存分配(创建Java对象时)和内存回收(回收Java对象)两个方面。这两方面工作都是由JVM自动完成的。

当Java对象被创建之后,垃圾回收机制会实时地监控每一个对象的运行状态,包括对象的申请,引用,被引用,赋值等。当垃圾回收机制实时地监控某个对象不再被引用变量所引用时,立即回收机制就会回收它所占用的空间。基本上,可以把JVM内存中对象引用理解成一种有向图,把引用变量,对象都当成为有向图的顶点,将引用关系当成图的有向边,有向边总是从引用端指向被引用的Java对象。因为Java所有对象都是由一条一条线程创建出来的,因此可把线程对象当成有向图的起始顶点。对于单线程而言,整个程序只有一条main线程,那么该图就是以main进程为顶点的有向图。在这个有向图中,main顶点可达的对象可达状态,垃圾回收机制不会回收它们;如果某个对象在这个有向图中处于不可达状态,那么就认为这个对象不再被引用,接下来垃圾回收机制就会主动回收它了。

class Node{

Node next;

String name;

public Node(String name){

this.name = name;

}

}

publicclass NodeTest {

publicstaticvoid main(String[] args){

Node n1 = new Node("The first node");

Node n2 = new Node("The second node");

Node n3 = new Node("The third node");

n1.next = n2;

n2 = null;

n3 = n2;

}

}

从main开始,有一条路径可带“The first node“,因此该对象处于可达状态,垃圾回收机制不会回收它;从main顶点开始,有两条路径可达”The second node”,因此该对象处于可达状态,垃圾回收机制也不会回收它;从main顶点开始,没有路径可以到达”The third node”,因此这个Java对象就变成了垃圾,接下来垃圾回收机制就会开始回收它。

采用有向图来管理内存中的对象具有高的精度,但是缺点是效率较低。

当一个对象在堆内存中运行时,根据它在对应有向图中的状态,可以把它所处的状态分成如下3种:

  1. 可达状态:当一个对象被创建后,有一个以上的引用变量引用它。在有向图中可从起始顶点到该对象,那它就处于可达状态,程序可通过引用变量来调用该对象的属性和方法。
  2. 可恢复状态:如果程序中某个对象不再有任何引用变量引用它,它将先进入可恢复状态,此时从有向图的起始顶点不能到达该对象。在这个状态下,系统的垃圾回收机制准备回收该对象所占用的内存。在回收该对象之前,系统会调用可恢复状态的对象的finalize方法进行资源清理,如果系统在调用finalize方法重新让一个以上引用变量引用该对象,则这个对象会再次变为可达状态;否则,该对象将进入不可达状态。
  3. 不可达状态:当对象的所有关联都被切断,且系统被调用所有对象的finalize方法依然没有使该对象变成可达状态,那这个对象将永久性地失去引用,最后变成不可达状态。只有当一个对象处于不可达状态时,系统才会真正回收该状态所占有的资源。

publicclass StatusTranfer {

publicstaticvoid test(){

String a = new String("aaa");

a = new String("bbb");

}

publicstaticvoid main(String[] args){

test();

}

}

当程序执行test方法的代码时,代码定义了一个a变量,并指向字符串”aaa”,字符串”aaa”处于可达状态,当执行完”bbb”后,“aaa“处于可恢复状态,”bbb”指向可达状态。

一个对象可以被一个方法局部变量所引用,也可以被其他类的类变量引用,或者被其他对象的实例变量性引用。当某个对象被其他类的类变量引用时,只有该类被销毁后,该对象才会进入可恢复状态;当某个对象被其他对象的实例变量引用时,只有当引用该变量的对象被销毁或变成不可达状态后,该对象才会进入不可达状态。

为了更好地管理对象的个,从JDK1.2开始,Java在java.lang.ref包下提供了3个类:SoftReference,PhantomReference和WeakReference.

程序创建一个对象,并把这个对象赋给一个引用变量,这个引用变量就是强引用。

Java程序可通过强引用来访问实际的对象,当一个对象被一个或多个强引用变量所引用时,它处于可达状态,它不可能被系统垃圾回收机制回收,即使是内存非常紧张的时候。因此它容易造成内存泄露。

软引用需要通过SoftReference类来实现,当一个对象只具有软引用时,它很可能被垃圾回收机制回收。对于只有软引用的对象而言,当系统内存空间足够时,不会被系统回收。

当程序需要大量创建某个类的新对象,而且有可能重新访问已创建来对象时可以充分使用软引用来解决内存紧张的难题。

例如,需要访问1000个Person对象,可以有两种方式:

  1. 一次创建1000个Person对象,但只有一个Person引用指向最后一个Person对象;
  2. 定义一个长度为1000的Person数组,每个数组元素引用一个Person对象。

第一种情况,程序不允许需要重新访问前面创建的对象,即使这个对象所占的堆空间还没有被回收。但已经失去了这个对象的引用,因此也不得不重新创建一个新的Person对象(重新分配内存)。而那个已有的Person对象则是等待被回收。

第二种情况,优势是可以随时重新访问前面创建的每个Person对象。弱点是如果系统堆内存空间紧张,而1000个Person对象都被强引用引用着,垃圾回收机制也不可能回收它们的堆内存空间,系统性能差。

如果使用软引用则是比较好的方案。如下:

import java.lang.ref.SoftReference;

class Person{

String name;

intage;

public Person(String name,int age){

this.name = name;

this.age = age;

}

public String toString(){

return"Person[name="+name+",age="+age+"]";

}

}

publicclass SoftReferenceTest {

publicstaticvoid main(String[] args){

SoftReference<Person>[] people = new SoftReference[10000000];

for(int i=0;i<people.length;i++){

people[i] = new SoftReference<Person>(new Person("name"+i,(i+1)*4%100));

}

System.out.println(people[2].get());

System.out.println(people[4].get());

System.gc();

System.runFinalization();

System.out.println(people[2].get());

System.out.println(people[4].get());

}

}

Output:

谈JAVA的内存回收(一)的更多相关文章

  1. 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制

    一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...

  2. 浅谈Java的内存模型以及交互

    本文的内存模型只写虚拟机内存模型,物理机的不予描述. Java内存模型 在Java中,虚拟机将运行时区域分成6中,如下图:              程序计数器:用来记录当前线程执行到哪一步操作.在多 ...

  3. Java的内存回收机制

    原文出处: cnblogs-小学徒V 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C ...

  4. [转载]Java的内存回收机制

    转自:http://www.admin10000.com/document/1671.html 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由J ...

  5. [java,2017-05-15] 内存回收 (流程、时间、对象、相关算法)

    内存回收的流程 java的垃圾回收分为三个区域新生代.老年代. 永久代 一个对象实例化时 先去看伊甸园有没有足够的空间:如果有 不进行垃圾回收 ,对象直接在伊甸园存储:如果伊甸园内存已满,会进行一次m ...

  6. Java jvm 内存回收机制

    http://blog.csdn.net/yaerfeng/article/details/51291903 在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方 ...

  7. Java的内存回收机制详解X

    http://blog.csdn.net/yqlakers/article/details/70138786 1 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前 ...

  8. Java的内存回收

    一.java引用的种类 1.对象在内存中的状态 可达状态:当一个对象被创建后,有一个以上的引用变量指向它. 可恢复状态: 不可达状态:当对象的所有关联被切断,且系统调用所有对象的finalize方法依 ...

  9. 浅谈Java堆内存分代回收

    目录 1.概述 2.堆内存是如何分代的 3.各分代之间是如何配合工作的 1.概述 与C++不同的是, 在Java中我们无需关心对象占用空间的释放, 这主要得益于Java中的垃圾处理器(简称GC)帮助我 ...

随机推荐

  1. object 属性 对象的继承 (原型, call,apply)

    object 为一切对象的基类! 属性:constructor: 对创建对象的函数的引用Prototype: 原型(类型) hasOwnProperty(property):判断对象是否有某个特定的属 ...

  2. LOL(英雄联盟)系统鼠标速度锁定工具

    最近习惯将系统的鼠标速度降低, 而提高鼠标硬件DPI来提升移动准确度, 但是LOL的客户端每次启动进入游戏后就会还原系统鼠标的移动速度, 我把情况反应给腾讯,没想到他们一点都不重视, 建议我只改游戏里 ...

  3. 头文件的宏定义#ifndef测试

    一.入题 在头文件的书写中,都加入了如下内容: #ifndef __头文件名_H #define __头文件名_H #endif 曾经在书中看到的解释是“防止重复定义”,今天突然想到为什么是这样的解释 ...

  4. Java集合类操作优化总结

    清单 1.集合类之间关系 Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHas ...

  5. Morgan stanley 电话面试

    首先是聊项目, 不会涉及到具体的技术问题 1.C和C++的区别:C++里的RTTI 2.vector 和 list的区别 : casting operator ; smart pointer. 3.数 ...

  6. 推荐一款不错的GIF录制软件附带.NET源码

    源码下载地址:http://www.51aspx.com/Code/ScreenToGif10

  7. APP二维码微信扫描后无法下载的问题

    微信打开网址添加在浏览器中打开提示  2014-10-13  蔡宝坚  移动前端 使用微信打开网址时,无法在微信内打开常用下载软件,手机APP等.网上流传的各种微信打开下载链接,微信已更新基本失效,最 ...

  8. 第 17 章 责任链模式【Chain of Responsibility Pattern】

    以下内容出自:<<24种设计模式介绍与6大设计原则>> 中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父.既嫁从夫.夫死从子”,也就是说一个女性,在没有结婚的 ...

  9. 【poj3070】矩阵乘法求斐波那契数列

    [题目描述] 我们知道斐波那契数列0 1 1 2 3 5 8 13…… 数列中的第i位为第i-1位和第i-2位的和(规定第0位为0,第一位为1). 求斐波那契数列中的第n位mod 10000的值. [ ...

  10. 使用SparseArray代替HashMap

    HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performanc ...