天天看点

Java弱引用、软引用、强引用、虚引用一、 概念。二、简单测试强引用、软引用和弱引用。三、如果弱引用或者虚引用的对象又有强引用,则不会被清除,继续上面的例子,修改测试方法,环境不变。四、常量不会被回收

一、 概念。

        强引用 -> Object strong = new Object(); ,类似这种代码,都是强引用,即使OutOfMemory,也不会被回收。通过设置strong = null,可以去除强引用。

        软引用 -> SoftReference,在OutOfMemory时被回收。用来描述一些还有用但是并非必须的对象。可以和一个引用队列(ReferenceQueue)联合使用,如果所引用的对象被垃圾回收器回收,Java虚拟机就会把这个引用加入到与之关联的引用队列中。

     弱引用->WeakReference,在垃圾回收器工作时,无论内存是否足够,都会被回收。可以和一个引用队列(ReferenceQueue)联合使用,如果所引用的对象被垃圾回收器回收,Java虚拟机就会把这个引用加入到与之关联的引用队列中。

        虚引用->PhantomReference,也称为幻影引用,一个对象是都有虚引用的存在都不会对其生存时间构成影响,也无法通过虚引来取得一个对象实例。唯一的用处:能在对象被回收时收到系统通知。

二、简单测试强引用、软引用和弱引用。

测试代码:

private static final int _1M = 1024 * 1024;

	private static void useprotosomaticAIP() {

		/* 分配1M,目前新生代空间使用1M */
		printPrepareMessage("strong1");
		LargeObject strong1 = new LargeObject(_1M, "strong1");

		/* 分配4M,目前新生代空间使用5M */
		SoftReference<LargeObject> soft1 = new SoftReference<LargeObject>(
				new LargeObject(2 * _1M, "soft1"));
		SoftReference<LargeObject> soft2 = new SoftReference<LargeObject>(
				new LargeObject(2 * _1M, "soft2"));

		/* 分配6M,目前新生代空间使用11M */
		WeakReference<LargeObject> weak1 = new WeakReference<LargeObject>(
				new LargeObject(3 * _1M, "weak1"));
		WeakReference<LargeObject> weak2 = new WeakReference<LargeObject>(
				new LargeObject(3 * _1M, "weak2"));

		/* 分配30M,触发GC和OutOfMemory */
		printPrepareMessage("strong2");
		LargeObject strong2 = new LargeObject(30 * _1M, "strong2");
	}

	static class LargeObject {
		private byte[] data;
		private String name;

		public LargeObject(int size, String name) {
			data = new byte[size];
			this.name = name;
			System.out.println("Over Constructing LargeObject " + name + System.lineSeparator());
		}

		public String getName() {
			return name;
		}
	}
           

测试环境:JDK1.8.0_144,Java HotSpot(TM) 64-Bit Server VM 

-Xms40m -Xmx40m -Xmn20m -XX:+PrintGCDetails

测试结果及分析:

Prepare to create strong1
Over Constructing LargeObject strong1

Over Constructing LargeObject soft1

Over Constructing LargeObject soft2

Over Constructing LargeObject weak1

Over Constructing LargeObject weak2

Prepare to create strong2

// 需要30M空间,内存不足,第一次MinorGC,回收弱引用的6M空间
[GC (Allocation Failure) [PSYoungGen: 12493K->2536K(17920K)] 12493K->5760K(38400K), 0.0026251 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

// 内存依旧不够,第二次MinorGC,无对象可回收
[GC (Allocation Failure) [PSYoungGen: 2536K->2504K(17920K)] 5760K->5728K(38400K), 0.0016023 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

// 内存依旧不够,第一次FullGC,eden space和from space的内存全部移入老年代
[Full GC (Allocation Failure) [PSYoungGen: 2504K->0K(17920K)] [ParOldGen: 3224K->5674K(20480K)] 5728K->5674K(38400K), [Metaspace: 2782K->2782K(1056768K)], 0.0061579 secs] [Times: user=0.00 sys=0.05, real=0.01 secs] 

// 内存依旧不够,第三次MinorGC,无对象可回收
[GC (Allocation Failure) [PSYoungGen: 0K->0K(17920K)] 5674K->5674K(38400K), 0.0002198 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
// 内存依旧不够,即将OutOfMemory,第二次FullGC,回收软引用的4M空间
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(17920K)] [ParOldGen: 5674K->1566K(20480K)] 5674K->1566K(38400K), [Metaspace: 2782K->2782K(1056768K)], 0.0049224 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

// 内存不足,打印异常
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.test.reference.TestReference$LargeObject.<init>(TestReference.java:84)
	at com.test.reference.TestReference.useprotosomaticAIP(TestReference.java:38)
	at com.test.reference.TestReference.main(TestReference.java:15)
Heap
 PSYoungGen      total 17920K, used 453K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)
  eden space 15360K, 2% used [0x00000000fec00000,0x00000000fec71678,0x00000000ffb00000)
  from space 2560K, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd80000)
  to   space 2560K, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x0000000100000000)
 ParOldGen       total 20480K, used 1566K [0x00000000fd800000, 0x00000000fec00000, 0x00000000fec00000)
  object space 20480K, 7% used [0x00000000fd800000,0x00000000fd9879e8,0x00000000fec00000)
 Metaspace       used 2812K, capacity 4490K, committed 4864K, reserved 1056768K
  class space    used 304K, capacity 386K, committed 512K, reserved 1048576K
           

三、如果弱引用或者虚引用的对象又有强引用,则不会被清除,继续上面的例子,修改测试方法,环境不变。

测试代码:

private static void referenceIsStrongUseProtosomaticAIP() {

		/* 分配1M,目前新生代空间使用1M */
		printPrepareMessage("strong1");
		LargeObject strong1 = new LargeObject(_1M, "strong1");

		LargeObject softObj1 = new LargeObject(2 * _1M, "softObj1");
		LargeObject softObj2 = new LargeObject(2 * _1M, "softObj2");
		
		/* 分配4M,目前新生代空间使用5M */
		SoftReference<LargeObject> soft1 = new SoftReference<LargeObject>(softObj1);
		SoftReference<LargeObject> soft2 = new SoftReference<LargeObject>(softObj2);

		LargeObject weakObj1 = new LargeObject(3 * _1M, "weakObj1");
		LargeObject weakObj2 = new LargeObject(3 * _1M, "weakObj2");
		
		/* 分配6M,目前新生代空间使用11M */
		WeakReference<LargeObject> weak1 = new WeakReference<LargeObject>(weakObj2);
		WeakReference<LargeObject> weak2 = new WeakReference<LargeObject>(weakObj2);

		/* eden区为16M,申请30M,触发MinorGC */
		printPrepareMessage("strong2");
		LargeObject strong2 = new LargeObject(30 * _1M, "strong2");
	}
           

测试环境:JDK1.8.0_144,Java HotSpot(TM) 64-Bit Server VM 

-Xms40m -Xmx40m -Xmn20m -XX:+PrintGCDetails

测试结果及分析:

Prepare to create strong1
Over Constructing LargeObject strong1

Over Constructing LargeObject softObj1

Over Constructing LargeObject softObj2

Over Constructing LargeObject weakObj1

Over Constructing LargeObject weakObj2

Prepare to create strong2


// 无内存可回收,因为弱引用的对象被强引用了
[GC (Allocation Failure) [PSYoungGen: 12493K->1704K(17920K)] 12493K->11952K(38400K), 0.0058929 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
// 无内存可回收,因为弱引用的对象被强引用了
[Full GC (Ergonomics) [PSYoungGen: 1704K->0K(17920K)] [ParOldGen: 10248K->11818K(20480K)] 11952K->11818K(38400K), [Metaspace: 2783K->2783K(1056768K)], 0.0095241 secs] [Times: user=0.05 sys=0.00, real=0.01 secs] 
// 无内存可回收,因为弱引用的对象被强引用了
[GC (Allocation Failure) [PSYoungGen: 0K->0K(17920K)] 11818K->11818K(38400K), 0.0003058 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
// 即将OOM,无内存可回收,因为软引用的对象被强引用了
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(17920K)] [ParOldGen: 11818K->11806K(20480K)] 11818K->11806K(38400K), [Metaspace: 2783K->2783K(1056768K)], 0.0059819 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.test.reference.TestReference$LargeObject.<init>(TestReference.java:170)
	at com.test.reference.TestReference.referenceIsStrongUseProtosomaticAIP(TestReference.java:66)
	at com.test.reference.TestReference.main(TestReference.java:22)
Heap
 PSYoungGen      total 17920K, used 453K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000)
  eden space 15360K, 2% used [0x00000000fec00000,0x00000000fec71678,0x00000000ffb00000)
  from space 2560K, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x0000000100000000)
  to   space 2560K, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd80000)
 ParOldGen       total 20480K, used 11806K [0x00000000fd800000, 0x00000000fec00000, 0x00000000fec00000)
  object space 20480K, 57% used [0x00000000fd800000,0x00000000fe387850,0x00000000fec00000)
 Metaspace       used 2813K, capacity 4494K, committed 4864K, reserved 1056768K
  class space    used 303K, capacity 386K, committed 512K, reserved 1048576K
           

四、常量不会被回收

测试代码:

private static void useConstantVariable() {

		WeakReference<String> weak1 = new WeakReference<String>("constant1");
		WeakReference<String> weak2 = new WeakReference<String>(new String("constant2"));
		System.gc();
		System.out.println(weak1.get());
		System.out.println(weak2.get());
	}
           

测试环境:JDK1.8.0_144,Java HotSpot(TM) 64-Bit Server VM 

测试结果及分析:

constant1 // "constant1"存在常量池,GC主要针对堆

null // "constant2"是在堆里面,所以会被GC