谈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. [python]类与类中的列表

    最近在用类中的列表时出现一件怪事 实例2中的列表,竟然有实例1中的数据. 查了半天发现是list的append方法的问题. 将全部的list.append(value) 换成 list = list ...

  2. ARM 的Thumb状态测试

    作为一个使用ARM的学习者,有必要全面了解你的处理器内核.尽管有些内容可能在实际应用中用不到,但是“了解”还是很必要的.Thumb状态,是ARM的一个特色,但是你知道Thumb状态与ARM状态最大的区 ...

  3. 解决DBCP报错 Could not retrieve transation read-only s

    dbcp连接池报错 commons-dbcp 解决Mysql Cannot get a connection, pool error:  Could not create a validated ob ...

  4. 使用 .NET 平台,如何玩转 Universal Windows 应用?

    2015年7月30日 本文作者是 Managed Languages 团队项目经理 Lucian Wischik. 不久前,Visual Studio 2015上新增 Windows 10 应用的开发 ...

  5. 李洪强iOS开发Swift篇—06_流程控制

    李洪强iOS开发Swift篇—06_流程控制 一.swift中的流程控制 Swift支持的流程结构如下: 循环结构:for.for-in.while.do-while 选择结构:if.switch 注 ...

  6. 常用模式之Command模式入门

    package com.zhao.cmd.a; /** * 客户端调用 * 烧烤摊 * * @author LuZhao * */ public class App { public static v ...

  7. WordPress WooCommerce ‘hide-wc-extensions-message’参数跨站脚本漏洞

    漏洞名称: WordPress WooCommerce ‘hide-wc-extensions-message’参数跨站脚本漏洞 CNNVD编号: CNNVD-201310-501 发布时间: 201 ...

  8. 用C++试着完成Python简明教程后面的练习

    试图存取文件的部分无法完成.代码已提交到github.

  9. Linux libtins 库安装教程

    因为工作原因需要用到libtins网络库, 所以今天去装一下. 很尴尬,由于本人对linux理解比较浅, 所以在中途遇到了一些问题. 虽然只是简单的安装步骤,但是阻挡不了自己菜啊. 一.  下载lib ...

  10. Intersoft Mobile Studio 2013 R1 SP1 Crack

    Intersoft Mobile Studio 2013 R1 SP1 (iOS, Android & WinR) Leave a comment   tweet       inShare ...