天天看点

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

           

对比

  • 强引用:不回收
  • 软引用:当系统内存充足时,不会被回收;不足时,会被回收.
  • 弱引用:回收
  • 虚引用:回收,配合引用队列使用