一:四种引用的概念
- 强引用
垃圾回收器在程序正常运行期间不会回收被强引用所引用的对象,即便是jvm可使用内存不足宁愿抛出OutOfMemoryError也不会回收所引用的对象
- 软引用
当jvm可使用内存不足时 且某对象只被软引用所引用 则垃圾回收器会将其进行回收从而释放内存
- 弱引用
无论jvm可使用内存是否充足 垃圾回收器随时都可能将只有弱引用所引用的对象进行回收
- 虚引用
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知
二:四种引用的使用场景
- 强引用
默认就是强引用 例如 Object target = new Object(); 其中target就是一个强引用
- 软引用
经常用于内存敏感的缓存(Soft references are most often used to implement memory-sensitive caches.)
- 弱引用
经常用于实现规范化映射(Weak references are most often used to implement canonicalizing mappings.) 典型应用 ThreadLocal 可以防止内存泄漏
- 虚引用
Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.
三:内存泄露和引用的关系
- 强引用导致内存泄漏
- 弱引用防止内存泄露
四:三种引用测试
测试时的运行参数,-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m -Xms5m -Xmx5m -Xmn5m -XX:+PrintGCDetails
- 强引用测试
private static class InnerObject {
//1M
private byte[] content = new byte[1024 * 1024];
}
/**
* 强引用不会被垃圾回收 当运行时内存不足时 程序报错
*/
private void testStrongReference() throws Exception {
Object target = new Object();
List<InnerObject> result = new ArrayList<>();
while(true){
result.add(new InnerObject());
System.gc();
Thread.sleep(100);
if(target == null){
System.out.println("testStrongReference gc work");
return;
}
}
}
[GC (Allocation Failure) [PSYoungGen: 4096K->511K(4608K)] 4096K->1033K(5632K), 0.0015845 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 511K->0K(4608K)] [ParOldGen: 521K->985K(1024K)] 1033K->985K(5632K), [Metaspace: 2560K->2560K(1056768K)], 0.0071854 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 2029K->1060K(4608K)] [ParOldGen: 985K->707K(1024K)] 3014K->1767K(5632K), [Metaspace: 3350K->3350K(1056768K)], 0.0066089 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 2329K->2107K(4608K)] [ParOldGen: 707K->703K(1024K)] 3037K->2810K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0068745 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 3184K->3131K(4608K)] [ParOldGen: 703K->703K(1024K)] 3887K->3834K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0031829 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 3131K->3131K(4608K)] [ParOldGen: 703K->703K(1024K)] 3834K->3834K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0055187 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (Allocation Failure) [PSYoungGen: 3131K->3126K(4608K)] [ParOldGen: 703K->690K(1024K)] 3834K->3816K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0071178 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.example.demo.ReferenceTest$InnerObject.<init>(ReferenceTest.java:18)
at com.example.demo.ReferenceTest$InnerObject.<init>(ReferenceTest.java:16)
at com.example.demo.ReferenceTest.testStrongReference(ReferenceTest.java:36)
at com.example.demo.ReferenceTest.main(ReferenceTest.java:23)
- 软引用测试
/**
* 软引用 当运行时内存不足且对象只被软引用时 回收被引用的软引用对象 并将自己添加到引用队列(可选)
*/
private void testSoftReference() throws Exception {
List<SoftReference> result = new ArrayList<>();
ReferenceQueue<InnerObject> referenceQueue = new ReferenceQueue();
while (true) {
result.add(new SoftReference(new InnerObject(),referenceQueue));
System.gc();
Thread.sleep(1000);
//发生jc时:SoftReference对象会加入到referenceQueue队列中并且SoftReference所引用的对象会被回收
if (referenceQueue.poll() != null && referenceQueue.poll().get() == null) {
System.out.println("testSoftReference gc work");
return;
}
}
}
[Full GC (System.gc()) [PSYoungGen: 2541K->1589K(4608K)] [ParOldGen: 534K->517K(1024K)] 3076K->2107K(5632K), [Metaspace: 3353K->3353K(1056768K)], 0.0078729 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC (System.gc()) --[PSYoungGen: 2695K->2695K(4608K)] 3213K->3293K(5632K), 0.0010570 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 2695K->2544K(4608K)] [ParOldGen: 597K->270K(1024K)] 3293K->2814K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0061513 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC (System.gc()) --[PSYoungGen: 3703K->3703K(4608K)] 3973K->3989K(5632K), 0.0008590 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 3703K->3553K(4608K)] [ParOldGen: 286K->283K(1024K)] 3989K->3836K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0051763 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) --[PSYoungGen: 3553K->3553K(4608K)] 3836K->3860K(5632K), 0.0015420 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (Ergonomics) [PSYoungGen: 3553K->0K(4608K)] [ParOldGen: 307K->746K(1024K)] 3860K->746K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0062311 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 1024K->1024K(4608K)] [ParOldGen: 746K->746K(1024K)] 1770K->1770K(5632K), [Metaspace: 3355K->3355K(1056768K)], 0.0030378 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
testSoftReference gc work
Heap
PSYoungGen total 4608K, used 1099K [0x00000007bfb00000, 0x00000007c0000000, 0x00000007c0000000)
eden space 4096K, 26% used [0x00000007bfb00000,0x00000007bfc12f00,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
ParOldGen total 1024K, used 746K [0x00000007bfa00000, 0x00000007bfb00000, 0x00000007bfb00000)
object space 1024K, 72% used [0x00000007bfa00000,0x00000007bfaba9e0,0x00000007bfb00000)
Metaspace used 3362K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 366K, capacity 388K, committed 512K, reserved 1048576K
- 软引用使用场景之一 全局缓存
//当作全局缓存使用 保存着SoftReference对象 当jvm内存不够用时 在抛出OutOfMemoryError之前会将SoftReference所引用的对象回收掉
private static List<SoftReference> result = new ArrayList<>();
/**
* 软引用 适用场景 cache
*/
private void testSoftReferenceApply() throws Exception {
while (true) {
result.add(new SoftReference<>(new InnerObject()));
System.gc();
Thread.sleep(1000);
if (result.get(0).get() == null) {
System.out.println("testSoftReferenceApply gc work");
return;
}
}
}
[GC (System.gc()) --[PSYoungGen: 2541K->2541K(4608K)] 3048K->3120K(5632K), 0.0019075 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 2541K->1516K(4608K)] [ParOldGen: 579K->253K(1024K)] 3120K->1769K(5632K), [Metaspace: 3332K->3332K(1056768K)], 0.0178724 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC (System.gc()) --[PSYoungGen: 2785K->2785K(4608K)] 3039K->3063K(5632K), 0.0017096 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 2785K->2551K(4608K)] [ParOldGen: 277K->260K(1024K)] 3063K->2811K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0059142 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (System.gc()) --[PSYoungGen: 3628K->3628K(4608K)] 3888K->3912K(5632K), 0.0011359 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 3628K->3559K(4608K)] [ParOldGen: 284K->276K(1024K)] 3912K->3835K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0100496 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) --[PSYoungGen: 3559K->3559K(4608K)] 3835K->3843K(5632K), 0.0013214 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 3559K->1497K(4608K)] [ParOldGen: 284K->272K(1024K)] 3843K->1769K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0057063 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC (System.gc()) --[PSYoungGen: 2521K->2521K(4608K)] 2793K->2793K(5632K), 0.0007451 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 2521K->2521K(4608K)] [ParOldGen: 272K->272K(1024K)] 2793K->2793K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0060053 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (System.gc()) --[PSYoungGen: 3579K->3579K(4608K)] 3852K->3852K(5632K), 0.0007360 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 3579K->3545K(4608K)] [ParOldGen: 272K->272K(1024K)] 3852K->3817K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0056777 secs] [Times: user=0.01 sys=0.01, real=0.00 secs]
[GC (Allocation Failure) --[PSYoungGen: 3545K->3545K(4608K)] 3817K->4161K(5632K), 0.0011826 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 3545K->1167K(4608K)] [ParOldGen: 615K->602K(1024K)] 4161K->1769K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0069898 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 2191K->2191K(4608K)] [ParOldGen: 602K->602K(1024K)] 2793K->2793K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0041360 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 3237K->3215K(4608K)] [ParOldGen: 602K->602K(1024K)] 3840K->3817K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0044236 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 3215K->3215K(4608K)] [ParOldGen: 602K->602K(1024K)] 3817K->3817K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0037571 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 3215K->0K(4608K)] [ParOldGen: 602K->745K(1024K)] 3817K->745K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0032253 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 1024K->1024K(4608K)] [ParOldGen: 745K->745K(1024K)] 1769K->1769K(5632K), [Metaspace: 3346K->3346K(1056768K)], 0.0029686 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
testSoftReferenceApply gc work
Heap
PSYoungGen total 4608K, used 1120K [0x00000007bfb00000, 0x00000007c0000000, 0x00000007c0000000)
eden space 4096K, 27% used [0x00000007bfb00000,0x00000007bfc18360,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
ParOldGen total 1024K, used 745K [0x00000007bfa00000, 0x00000007bfb00000, 0x00000007bfb00000)
object space 1024K, 72% used [0x00000007bfa00000,0x00000007bfaba750,0x00000007bfb00000)
Metaspace used 3354K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 366K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0
- 弱引用测试
/**
* 弱引用
* 当对象只有被弱引用所引用时 随时可能被gc线程回收 并将自己添加到引用队列(可选)
*/
private void testWeakReference() throws Exception {
WeakReference<Object> wre = new WeakReference<>(new InnerObject());
List<InnerObject> result = new ArrayList<>();
while (true) {
result.add(new InnerObject());
System.gc();
Thread.sleep(1000);
if (wre.get() == null) {
System.out.println("testWeakReference gc work");
return;
}
}
}
[GC (Allocation Failure) [PSYoungGen: 4096K->511K(4608K)] 4096K->1033K(5632K), 0.0016185 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 511K->0K(4608K)] [ParOldGen: 521K->985K(1024K)] 1033K->985K(5632K), [Metaspace: 2560K->2560K(1056768K)], 0.0074174 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 3053K->1024K(4608K)] [ParOldGen: 985K->744K(1024K)] 4038K->1768K(5632K), [Metaspace: 3351K->3351K(1056768K)], 0.0075642 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
testWeakReference gc work
Heap
PSYoungGen total 4608K, used 1268K [0x00000007bfb00000, 0x00000007c0000000, 0x00000007c0000000)
eden space 4096K, 30% used [0x00000007bfb00000,0x00000007bfc3d188,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
ParOldGen total 1024K, used 744K [0x00000007bfa00000, 0x00000007bfb00000, 0x00000007bfb00000)
object space 1024K, 72% used [0x00000007bfa00000,0x00000007bfaba080,0x00000007bfb00000)
Metaspace used 3363K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 366K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0