A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

© 小痞痞 高级黑马   /  2013-12-3 20:19  /  1008 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

内存回收机制

在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。

内存管理小技巧
  • 尽量使用直接量,如 String str = "xxx"
  • 使用 StringBuilderStringBuffer进行字符串连接等操作。
  • 尽早释放无用对象
  • 尽量少使用静态变量
  • 缓存常用的对象,可以使用开源缓存实现(OSCache,Ehcache)
  • 尽量不使用 finalize()方法
  • 在必要时可以考虑软引用 (SoftReference)。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马