谈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. 如何判断一个Div是否在可视区域,判断div是否可见

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. apache2.2+PHP5.4.28

    搭建apache+php开发环境,apache一路正常安装,但是,下载的php搭建后,配置好apache.php,始终报错“The requested operation has failed!”换了 ...

  3. 操作系统和Python的发展历程

    一:操作系统的发展历史: 操作系统:什么是操作系统?我们首先想到的是电脑,,也就是所谓的Windows8,Windows7,或者XP系统和Windows10,当然也包括我们手机的安卓系统或者IPhon ...

  4. 整理 iOS 9 适配中出现的坑(图文)

    作者:董铂然 授权本站转载. 本文主要是说一些iOS9适配中出现的坑,如果只是要单纯的了解iOS9新特性可以看瞄神的开发者所需要知道的 iOS 9 SDK 新特性.9月17日凌晨,苹果给用户推送了iO ...

  5. ubuntu导出文件

    ye@aliyun:python$ ./deploy.sh backup static-rw-r--r-- 1 ye ye 174K 2014-03-22 10:36 ./backup/fbz_sta ...

  6. jMeter之二

    jMeter应用的最小子集有如下三个概念: 首先是线程组(Thread Group),线程组意味着定义一下多少个线程,多长时间建立起来(模拟增量按照一定频度上扬)以及循环多少次: 第二个是采样器(Sa ...

  7. WordPress标题函数wp_title()详解

    在wp_title()中通常是在页面头部的title元素中.当wp_title()在主页主循环(loop)外时,可以用在模板的任何地方. 用法: <?php wp_title( $sep, $e ...

  8. JAVA 时间差距,两个时间相差多少天,时,分,秒

    JAVA 时间差距,两个时间相差多少天,时,分,秒 package io; import java.text.DateFormat; import java.text.ParseException; ...

  9. NWERC 2012 Problem A Admiral

    一个最小费用最大流的简单建模题: 比赛的时候和小珺合力想到了这个题目的模型: 方法:拆点+边的容量为1 这样就可以保证他们不会在点上和边上相遇了! 感谢刘汝佳大神的模板,让我这个网络流的小白A了这个题 ...

  10. jquery mobile backbone

    http://www.appliness.com/getting-started-with-html-mobile-application-development-using-jquery-mobil ...