天天看點

JVM_3_強引用,軟引用,弱引用,虛引用分析JVM_3_強引用,軟引用,弱引用,虛引用分析

文章目錄

  • JVM_3_強引用,軟引用,弱引用,虛引用分析
    • 強引用
      • 概念
      • 示例
    • 軟引用
      • 概念
      • 示例
    • 弱引用
      • 概念
      • 示例
      • 應用
      • WeakHashMap
    • 虛引用
      • 概念
      • 示例
        • 引用隊列
        • demo
    • 對比

JVM_3_強引用,軟引用,弱引用,虛引用分析

強引用

概念

  • 當記憶體不足,JVM開始垃圾回收,對于強引用對象,就算出現OOM,也不會對該對象回收.
  • 強引用是造成java記憶體洩漏的主要原因之一

示例

package top.ygy.jvm;

/**
 * @Description: TODO(強引用)
 * @author yangguangyuan
 * @date 2019年6月28日
 * obj2未被回收掉
 */
public class StrongReferenceDemo {
	public static void main(String[] args) {
		Object obj1 = new Object();
		Object obj2 = obj1;
		obj1 = null;
		System.gc();
		System.out.println(obj2);
	}
}
           

軟引用

概念

  • 軟引用是一種相對強引用弱化了一些的引用,需要用java.lang.ref.SoftReference類來實作,可以讓對象豁免一些垃圾收集.
  • 對于隻有軟引用的對象來說
    • 當系統記憶體充足時,不會被回收.
    • 當系統記憶體不足時,會被回收.
  • 用途:軟引用通常用在對記憶體敏感的程式中,比如高速緩存就用到軟引用,記憶體夠用就保留,不夠用就回收.

示例

package top.ygy.jvm;

import java.lang.ref.SoftReference;

/**
 * @Description: TODO(軟引用)
 * @author yangguangyuan
 * @date 2019年6月28日
 */
public class SoftReferenceDemo {

	public static void main(String[] args) {

		softRef_Memory_NotEnough();
	}

	/**
	 * JVM配置,故意生産大對象并配置小記憶體,讓它記憶體不夠用導緻OOM,看軟引用的回收情況 
	 * -Xms5m -Xmx5m -XX:+PrintGCDetails
	 */
	public static void softRef_Memory_NotEnough() {
		Object o1 = new Object();
		SoftReference<Object> softReference = new SoftReference<>(o1);
		System.out.println(o1);
		System.out.println(softReference.get());

		o1 = null;
		System.gc();

		try {
			byte[] byte1 = new byte[30 * 1024 * 1024];
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println(o1);
			System.out.println(softReference.get());
		}
	}
}

           
  • 記憶體夠用結果
java.lang.Object@76ccd017
java.lang.Object@76ccd017
null
java.lang.Object@76ccd017

           
  • 記憶體不夠用結果

    -Xms5m -Xmx5m -XX:+PrintGCDetails

java.lang.Object@7852e922
java.lang.Object@7852e922
[GC (System.gc()) [PSYoungGen: 841K->488K(1536K)] 841K->592K(5632K), 0.0007545 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 488K->0K(1536K)] [ParOldGen: 104K->558K(4096K)] 592K->558K(5632K), [Metaspace: 2777K->2777K(1056768K)], 0.0048971 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 558K->558K(5632K), 0.0002058 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 558K->558K(5632K), 0.0001498 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 558K->558K(4096K)] 558K->558K(5632K), [Metaspace: 2777K->2777K(1056768K)], 0.0018644 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 558K->558K(5632K), 0.0001540 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 558K->546K(4096K)] 558K->546K(5632K), [Metaspace: 2777K->2777K(1056768K)], 0.0044638 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
null
null
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at top.ygy.jvm.SoftReferenceDemo.softRef_Memory_NotEnough(SoftReferenceDemo.java:31)
	at top.ygy.jvm.SoftReferenceDemo.main(SoftReferenceDemo.java:14)
Heap
 PSYoungGen      total 1536K, used 30K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
  eden space 1024K, 3% used [0x00000000ffe00000,0x00000000ffe07b08,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 4096K, used 546K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
  object space 4096K, 13% used [0x00000000ffa00000,0x00000000ffa888f0,0x00000000ffe00000)
 Metaspace       used 2808K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 303K, capacity 386K, committed 512K, reserved 1048576K

           

弱引用

概念

  • 弱引用需要用java.lang.ref.WeakReference類來實作,它比軟引用的生存期更短
  • 對于隻有弱引用,隻要垃圾回收機制一運作,不管JVM記憶體是否足夠,都會回收該對象占用的記憶體

示例

package top.ygy.jvm;

import java.lang.ref.WeakReference;

/**
 * @Description: TODO(弱引用示例)
 * @author yangguangyuan
 * @date 2019年6月28日
 *
 */
public class WeakReferenceDemo {
	public static void main(String[] args) {
		Object o1 = new Object();
		WeakReference<Object> weakReference = new WeakReference<>(o1);
		System.out.println(o1);
		System.out.println(weakReference.get());
		
		o1 = null;
		System.gc();

		System.out.println(o1);
		System.out.println(weakReference.get());
	}
}
           

應用

  • 問題:假如有一個應用需要讀取大量的本地圖檔?
  • 分析
    • 每次都從硬碟讀取影響性能.
    • 一次性全部加載到記憶體中又可能造成記憶體溢出.
  • 解決:使用軟引用解決

    設計思路:用一個HashMap來儲存圖檔的路徑和相應圖檔對象關聯的軟引用之間的映射關系,在記憶體不足時,JVM會自動回收這些緩存圖檔對象所占用的空間,進而有效的避免了OOM的問題.

WeakHashMap

  • 代碼
package top.ygy.jvm;

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

/**
 * @Description: TODO(WeakHashMap)
 * @author yangguangyuan
 * @date 2019年6月28日
 *
 */
public class WeakHashMapDemo {
	public static void main(String[] args) {
		myHashMap();
		System.out.println("**********************************");
		myWeakHashMap();
	}

	private static void myHashMap() {
		Map<Integer, String> map = new HashMap<>();
		Integer key = new Integer(1);
		String value = "HashMap";

		map.put(key, value);
		System.out.println(map);

		key = null;
		System.out.println(map);

		System.gc();
		System.out.println(map + "\t" + map.size());
	}
	
	private static void myWeakHashMap() {
		Map<Integer, String> map = new WeakHashMap<>();
		Integer key = new Integer(2);
		String value = "WeakHashMap";

		map.put(key, value);
		System.out.println(map);

		key = null;
		System.out.println(map);

		System.gc();
		System.out.println(map + "\t" + map.size());
	}
}
           

結果:

{1=HashMap}
{1=HashMap}
{1=HashMap}	1
**********************************
{2=WeakHashMap}
{2=WeakHashMap}
{}	0
           
  • 對比
    • HashMap:強引用
    • WeakHashMap:弱引用
  • 應用
    • 做高速緩存和對記憶體敏感的相關業務

虛引用

概念

  • 虛引用需要java.lang.ref.PhantomReference類來實作
  • “虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
  • 虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的記憶體之前,把這個虛引用加入到與之 關聯的引用隊列中。
  • 作用:跟蹤對象被垃圾回收的狀态,僅僅是提供了一種確定對象被finalize以後,做某些事情的機制.

示例

引用隊列

package top.ygy.jvm;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;

public class ReferenceQueueDemo {
	public static void main(String[] args) {
		Object o1 = new Object();
		ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
		WeakReference<Object> weakReference = new WeakReference<>(o1, referenceQueue);
		
		System.out.println(o1);
		System.out.println(weakReference.get());
		System.out.println(referenceQueue.poll());
		
		System.out.println("**********************");
		o1 = null;
		System.gc();

		System.out.println(o1);
		System.out.println(weakReference.get());
		System.out.println(referenceQueue.poll());
	}
}

           

結果:

java.lang.Object@7852e922
java.lang.Object@7852e922
null
**********************
null
null
java.lang.ref.WeakReference@4e25154f


           

demo

package top.ygy.jvm;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceDemo {
	public static void main(String[] args) {
		Object o1 = new Object();
		ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
		PhantomReference<Object> weakReference = new PhantomReference<>(o1, referenceQueue);
		
		System.out.println(o1);
		System.out.println(weakReference.get());
		System.out.println(referenceQueue.poll());
		
		System.out.println("**********************");
		o1 = null;
		System.gc();

		System.out.println(o1);
		System.out.println(weakReference.get());
		System.out.println(referenceQueue.poll());
	}
}

           

結果:

java.lang.Object@7852e922
null
null
**********************
null
null
java.lang.ref.PhantomReference@4e25154f

           

對比

  • 強引用:不回收
  • 軟引用:當系統記憶體充足時,不會被回收;不足時,會被回收.
  • 弱引用:回收
  • 虛引用:回收,配合引用隊列使用