java语言从诞生开始,一个吸引人眼球的功能就是垃圾回收,想一想C++中时不时的内存泄漏,当时感觉写java代码直是一种享受呀。 和.NET的引用计数不同,java的垃圾回收机制采取的是有向图的方式来实现,具体的说,java程序中的每个线程对象就可以看作是一个有向图的起点,有向边从栈中的引用者指向堆中的引用对象。在这个有向图中,如果一个对象和根节点之间是可达的,那么这个对象就是有效的,反之,这个对象就是可以被回收的。采取这样一种机制的优点是可以有效的避免循环引用。 java语言中的对象引用分为以下几种:强引用、软引用、弱引用和虚引用。 强引用就是我们经常用到的引用,这种引用在对象被标识为无效后,不会被立刻回收,除非写o = null;这种语句。 软引用,如果一个被软引用的对象被标识为无效后,在内存控件足够的情况下,不会被回收,在内存紧张的情况下,会被回收的。 弱引用,如果一个被弱引用的对象被标识为无效,那么对象会被立刻回收。 虚引用,这是一种不太真实可用的引用类型,它的主要用途是结合引用关联队列,实现对对象引用关系的跟踪。 四种引用的Sample如下:
1 import java.lang.ref.SoftReference;
2 import java.lang.ref.WeakReference;3 import java.lang.ref.PhantomReference;4 import java.lang.ref.ReferenceQueue;5 import java.util.HashSet;6 import java.util.Set;78 class MyObject { 9 private String id;10 11 public MyObject(String id) { 12 this.id = id;13 }14 15 public String toString() { 16 return id;17 }18 19 public void finalize() { 20 System.out.println("Object Collect: " + id);21 }22}2324 public class ReferenceTest { 25 26 public static void main(String[] args) { 27 // TODO Auto-generated method stub28 29 int length = 10;30 31 Set<MyObject> a = new HashSet<MyObject>();32 for (int i = 0; i < length; i++) { 33 MyObject ref = new MyObject("Hard_" + i);34 System.out.println("Create Strong Refence: " + ref);35 a.add(ref);36 }37 System.out.println();38 System.gc();39 System.out.println();40 41 Set<SoftReference<MyObject>> sa = new HashSet<SoftReference<MyObject>>();42 for (int i = 0; i < length; i++) { 43 SoftReference<MyObject> ref = new SoftReference<MyObject>(new MyObject("Soft_" + i));44 System.out.println("Create Soft Refence: " + ref);45 sa.add(ref);46 }47 System.out.println();48 System.gc();49 System.out.println();50 51 Set<WeakReference<MyObject>> wa = new HashSet<WeakReference<MyObject>>();52 for (int i = 0; i < length; i++) { 53 WeakReference<MyObject> ref = new WeakReference<MyObject>(new MyObject("Weak_" + i));54 System.out.println("Create Weak Refence: " + ref);55 wa.add(ref);56 }57 System.out.println();58 System.gc();59 System.out.println();6061 ReferenceQueue rq = new ReferenceQueue<MyObject>();62 Set<PhantomReference<MyObject>> pa = new HashSet<PhantomReference<MyObject>>();63 for (int i = 0; i < length; i++) { 64 //MyObject ref = new MyObject("Hard_" + i);65 PhantomReference<MyObject> ref = new PhantomReference<MyObject>(new MyObject("Phantom_" + i), rq);66 System.out.println("Create Phantom Refence: " + ref);67 pa.add(ref);68 }69 System.out.println();70 System.gc();71 System.out.println();72 }执行结果如下:
Create Strong Refence: Hard_0 Create Strong Refence: Hard_1 Create Strong Refence: Hard_2 Create Strong Refence: Hard_3 Create Strong Refence: Hard_4 Create Strong Refence: Hard_5 Create Strong Refence: Hard_6 Create Strong Refence: Hard_7 Create Strong Refence: Hard_8 Create Strong Refence: Hard_9 Create Soft Refence: java.lang.ref.SoftReference@1270b73 Create Soft Refence: java.lang.ref.SoftReference@60aeb0 Create Soft Refence: java.lang.ref.SoftReference@16caf43 Create Soft Refence: java.lang.ref.SoftReference@66848c Create Soft Refence: java.lang.ref.SoftReference@8813f2 Create Soft Refence: java.lang.ref.SoftReference@1d58aae Create Soft Refence: java.lang.ref.SoftReference@83cc67 Create Soft Refence: java.lang.ref.SoftReference@e09713 Create Soft Refence: java.lang.ref.SoftReference@de6f34 Create Soft Refence: java.lang.ref.SoftReference@156ee8e Create Weak Refence: java.lang.ref.WeakReference@e0e1c6 Create Weak Refence: java.lang.ref.WeakReference@6ca1c Create Weak Refence: java.lang.ref.WeakReference@1bf216a Create Weak Refence: java.lang.ref.WeakReference@12ac982 Create Weak Refence: java.lang.ref.WeakReference@1389e4 Create Weak Refence: java.lang.ref.WeakReference@c20e24 Create Weak Refence: java.lang.ref.WeakReference@2e7263 Create Weak Refence: java.lang.ref.WeakReference@157f0dc Create Weak Refence: java.lang.ref.WeakReference@863399 Create Weak Refence: java.lang.ref.WeakReference@a59698 Create Phantom Refence: java.lang.ref.PhantomReference@5740bb Create Phantom Refence: java.lang.ref.PhantomReference@5ac072 Create Phantom Refence: java.lang.ref.PhantomReference@109a4c Create Phantom Refence: java.lang.ref.PhantomReference@201f9 Create Phantom Refence: java.lang.ref.PhantomReference@1cf8583 Create Phantom Refence: java.lang.ref.PhantomReference@14693c7 Create Phantom Refence: java.lang.ref.PhantomReference@901887 Create Phantom Refence: java.lang.ref.PhantomReference@3a6727 Create Phantom Refence: java.lang.ref.PhantomReference@4a65e0 Create Phantom Refence: java.lang.ref.PhantomReference@665753 Object Collect: Phantom_6 Object Collect: Phantom_9 Object Collect: Phantom_8 Object Collect: Phantom_7 Object Collect: Phantom_5 Object Collect: Phantom_4 Object Collect: Phantom_3 Object Collect: Phantom_2 Object Collect: Phantom_1 Object Collect: Phantom_0 Object Collect: Weak_9 Object Collect: Weak_8 Object Collect: Weak_7 Object Collect: Weak_6 Object Collect: Weak_5 Object Collect: Weak_4 Object Collect: Weak_3 Object Collect: Weak_2 Object Collect: Weak_1 Object Collect: Weak_0 虽然java语言采取了比.NET更好的垃圾回收机制,但是它也存在内存泄漏的时候,考虑以下情况:
1 Vector v = new Vector(10); 2 for (int i = 0; i < 10; i++) { 3 object o = new object(); 4 v.add(o); 5 o = null; 6 }
对于每次建立的对象o,虽然最后通过o = null;语句来表明它是无效的,但是我们可以通过Vector来引用到它,这样,如果在Vector使用完毕后没有被显示的释放,即没有v = null;的话,这里就产生了内存泄漏。