一、简介
java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象,对象的引用包括:
1.强引用:使用 new 这个关键字创建对象时创建出来的对象就是强引用。GC宁愿抛出OutOfMemoryError也不会回收有强引用的对象。
2.软引用SoftReference:软引用的对象如果内存空间足够,GC不会回收,如果内存空间不足,就会回收该对象。可以和引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被回收,就会把这个软引用加入到与之关联的引用队列中。软引用可用来实现内存敏感的缓存。
3.弱引用WeakReference:弱引用的对象拥有更短暂的生命周期,只要GC工作,发现就回收,也可和引用队列联合使用。ThreadLocal的内部类ThreadLocalMap的静态内部类Entry继承了WeakReference。
4.虚引用PhantomReference:在任何时候都可能被垃圾回收,必须和引用队列联合使用,并且通过get()方法获取不到引用对象。被用来做堆外内存的监控(Netty)。
二、代码演示效果
1.强引用
public class StrongReference {
public static void main(String[] args) {
ReferenceTest o = new ReferenceTest();
//引用指向null 将这行注释掉 执行结果不打印"我被回收了"
o = null;
//回收
System.gc();
//主线程一直睡
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ReferenceTest {
@Override
protected void finalize() throws Throwable {
System.out.println("我被回收了");
}
}
2.软引用
public class SoftReferenceTest {
public static void main(String[] args) {
//一个大小为10M的软引用数组
SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024*1024*10]);
System.out.println(softReference.get());
System.gc();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(softReference.get());
//创建大小为15M 的字节数组
byte[] bytes = new byte[1024*1024*15];
//设置内存大小为20M 所以 软引用会被回收 返回null
System.out.println(softReference.get());
}
}
设置运行内存为20M:
执行结果:
3.弱引用
public class WeakReferenceTest {
public static void main(String[] args) {
WeakReference<ReferenceTest> weakReference = new WeakReference(new ReferenceTest());
System.out.println(weakReference.get());
System.gc();
System.out.println(weakReference.get());
}
}
效果:
4.虚引用:
public static void main(String[] args) {
//填冲内存 触发GC
List<byte[]> bytes = new ArrayList<>();
//引用队列
ReferenceQueue<ReferenceTest> queue = new ReferenceQueue<>();
//虚引用
PhantomReference<ReferenceTest> phantomReference = new PhantomReference<>(new ReferenceTest(), queue);
System.out.println(phantomReference.get());
new Thread(() -> {
while (true){
bytes.add(new byte[1024*1024*1]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(phantomReference.get());
}
}).start();
new Thread(() -> {
while (true){
Reference<? extends ReferenceTest> poll = queue.poll();
if (null != poll){
System.out.println("虚引用对象被回收了" + poll);
}
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
内存设置:
效果图:
注意:Java中提供这四种引用类型主要有两个目的:
- 是可以让程序员通过代码的方式决定某些对象的生命周期。
- 是有利于JVM进行垃圾回收。