黑马程序员技术交流社区

标题: java——内存回收机制 [打印本页]

作者: 小痞痞    时间: 2013-12-3 20:19
标题: java——内存回收机制
内存回收机制

在java中,内存管理包括两个方面: 内存分配(创建java对象)内存回收。这两个方面都是由jvm自动完成的。

java在内存中的状态

先看以下代码

  1. import java.io.Serializable;

  2. public class Person implements Serializable
  3. {
  4.     static final long serialVersionUTD = 1L;
  5.     String name;
  6.     Person friend;
  7.     public Person(){}
  8.     public Person(String name)
  9.     {
  10.         super();
  11.         this.name=name;
  12.     }
  13. }

  14. public class Test
  15. {
  16.     public static void main(String[] args)
  17.     {
  18.         Person p1 = new Person("Kevin");
  19.         Person p2 = new Person("Rain");
  20.         Person p3 = new Person("Sunny");

  21.         p1.friend = p2;
  22.         p3 = p2;
  23.         p2 = null;
  24.     }
  25. }
复制代码

把上面对象引用图画成一个从 main方法开始的对象引用图就是这样的:

当程序运行起来后,把它的内存看成有向图,可以分为三种:

可达状态

在一个对象创建之后,有一个以上的引用变量引用它。在有向图中可以从起始点到该对象。

可恢复状态

如果程序中某个对象不再有任何的引用变量引用它(曾经有),他就可以先进入 可恢复状态,此时有向图是不能到达他的。

在这个状态下,系统的垃圾回收机制准备回收该对象所占用的内存。在回收前,系统会调用 finalize()进行资源清理。

如果资源清理后,有一个以上的引用变量 重新引用该对象,则其变回 可达状态,反正就进入**不可达状态**。

不可达状态

当对象的所有联系都被切断,且系统调用finalize()方法对资源进行清理后,仍旧没有引用对象引用,则变成 不可达对象,这时系统就会真正地去回收该对象。
一图表达:

java对象的四种引用强引用

创建一个对象,并把该对象直接复制给一个变量,如 Person person = new Person("sunny");。

不管系统资源多么紧张,都不会回收。

软引用

软引用是通过 SoftReference类实现的,如 SoftReference<Person> person = new SoftReference<Peson>( new Person("rain"))。

内存非常紧张时,会对其进行回收,其他时候则不会回收,所以在使用之前要进行null判断再使用。

弱引用

弱引用是通过 WeakReference类实现的,如 WeakReference<Person> p = new WeakReference<Person>( new Person("rain") );

不管内存够不够,在进行垃圾回收时,都会进行回收。

虚引用

不能单独引用,主要是用于追踪对象被垃圾回收的状态,通过 PhantomReference类和引用队列 ReferenceQueue类联合使用实现。

垃圾回收机制

java垃圾回收主要做两件事, 内存回收碎片整理

垃圾回收算法串行回收和并行回收

串行回收是不管系统有多少个cpu,都只用一个cpu来执行垃圾回收操作。

并行回收是把整个回收拆分成多个部分,每个部分由一个cpu负责,从而让多个cpu并行回收。
并行回收执行效率高,但是复杂度也高。

并行执行和应用停止

应用程序停止(Stop-the-world):其垃圾回收时,会导致程序暂停。

并发执行的垃圾回收虽然不会导致应用程序的暂停,但由于并发执行垃圾需要解决和应用程序的执行冲突,因此开销大,而且需要更多的堆内存。

压缩和不压缩和复制

支持压缩的垃圾回收器(标记-压缩 = 标记清除+压缩):会把所有的可达对象搬迁在一齐,然后将之前占用的内存全部回收,减少碎片。

不压缩的垃圾回收器(标记-清除):要遍历两次,第一先从根开始访问所有可达对象,并标记他们为可达状态;第二次便利用整个内存区域,对未标记可达状态的对象进行回收处理。

这种方式,不压缩,不需要额外内存,但要遍历两次。 (跟js的垃圾回收方式有点像)

复制式的垃圾回收器

将堆内存分成两个相同的空间,从根开始访问每一个关联的可达对象,将空间A的全部可达对象复制到空间B,然后一次性回收空间A。

内存管理小技巧





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2