文章目錄
- 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
對比
- 強引用:不回收
- 軟引用:當系統記憶體充足時,不會被回收;不足時,會被回收.
- 弱引用:回收
- 虛引用:回收,配合引用隊列使用