1. 程式人生 > >一個記憶體洩漏的例子

一個記憶體洩漏的例子

記憶體洩漏

看一個例子:

class Stack {
		private Object[] elements;
		private int size = 0;
		private static final int DEFAULT_INITIAL_CAPACITY = 16;

		public Stack() {
			elements = new Object[DEFAULT_INITIAL_CAPACITY];
		}

		public void push(Object e) {
			ensureCapacity();
			elements[size++] = e;
} public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } public void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } }

這段程式碼存在一個記憶體洩漏問題:如果一個棧先增長,再收縮,那麼從棧中彈出的元素不會被當做垃圾回收;即使棧的程式不在引用這些物件,他們也不會被回收.
這是因為,棧內部維護著這些物件的過期引用

;過期引用是指永遠不再會被解除的引用.
記憶體洩漏的來源可能:

  • 自己管理記憶體的類,如Stack;
  • 快取(使用weakHashMap或由後臺執行緒定時清理)
  • 監聽器和其他回撥
    Stack正是由於自己管理記憶體的特性使它容易遭受記憶體洩漏的影響;

修復:一旦物件引用已經過期,只需清理這些引用即可;對於上面的例子而言,一旦元素從棧中彈出,指向它的引用就過期了;pop方法修改如下:

public Object pop() {
			if (size == 0)
				throw new EmptyStackException();
			Object result =
elements[--size]; element[size]=null//消除過期引用 return result ; }

weakHashMap

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;

public class WeakHashMapTester {
	static Map<String, String> wMap = new WeakHashMap<String, String>();
	static Map<String, String> map = new HashMap<String, String>();

	static {
		String ref1 = new String("obejct1");
		String ref2 = new String("obejct2");
		wMap.put(ref1, "chaheObject1");
		map.put(ref2, "chaheObject2");
	}

	public static void TestWeahHashMap() {
		System.out.println("WeakHashMap GC之前");
		for (Entry<String, String> str : wMap.entrySet()) {
			System.out.println(str);
		}

		System.gc();
		System.out.println("WeakHashMap GC之後");
		for (Entry<String, String> str : wMap.entrySet()) {
			System.out.println(str);
		}
	}

	public static void TestHashMap() {
		System.out.println("HashMap GC之前");
		for (Entry<String, String> str : map.entrySet()) {
			System.out.println(str);
		}

		System.gc();
		System.out.println("HashMap GC之後");
		for (Entry<String, String> str : map.entrySet()) {
			System.out.println(str);
		}
	}

	public static void main(String[] args) {
		TestWeahHashMap();
		System.out.println("---------");
		TestHashMap();
	}
}

結果:

WeakHashMap GC之前
obejct1=chaheObject1
WeakHashMap GC之後
---------
HashMap GC之前
obejct2=chaheObject2
HashMap GC之後
obejct2=chaheObject2

更多:https://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java/6471947#6471947
Effective java