1. java中的引用(Reference)
引用是java中堆和栈的桥梁,想要访问堆中的对象,就必须通过引用来访问(8个基本数据类型除外) 在垃圾回收中,如果一个对象仍然被GcRoots引用,那么就不会被回收(强引用),这也不是绝对的,主要是根据引用类型来决定的 ?
在jvm中也有对于的抽象类 Reference
package java.lang.ref;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.access.JavaLangRefAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.ref.Cleaner;
public abstract class Reference<T> {
...
}
并且软/弱/虚引用分别都有对于的实现类
1.1 引用分类
引用类型主要分为四类,四种引用在垃圾回收时表现不同
- 强引用 不回收
- 软引用 内存不足时回收
- 弱引用 发现即回收
- 虚引用 对象跟踪回收
由强到虚,回收级别递增.
1.1.1 强引用(StrongReference)
开发过程中的用的基本都是强引用
String str = new String("hello world");
这种最常见的创建对象的方式就是强引用. 这种引用jvm是不会进行回收的,只有当引用被置为null的时候,jvm才会进行回收. ?
例子证明:
public class Test1 {
public static void main(String[] args) {
String str = new String("hello world");
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(str);
}
}
一般情况下,出现内存泄漏的问题都是因为强引用. ?
1.1.2 软引用(SoftReference)
软引用是用来做一些非必要但是还有用的对象. 例如缓存 当内存不足时,软引用会被回收. 具体的逻辑为:
- 内存空间不足,进行垃圾回收,回收不可达对象
- 不可达对象回收后,内存空间依然不足,进行软引用的回收
- 如果软引用回收后,内存空间依然不足,报错OOM,如果内存空间足够,则不报OOM
软引用在jdk中有对应的实现类
package java.lang.ref;
public class SoftReference<T> extends Reference<T> {
...
}
我们用一个例子证明软引用在内存不足时会被回收:
import java.lang.ref.SoftReference;
public class SoftReferenceTest {
public static void main(String[] args) {
SoftReference hello_world = new SoftReference(new String("hello world"));
System.out.println(hello_world.get().toString());
try {
byte[] bytes = new byte[1024 * 1024 * 10];
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("垃圾回收后");
System.out.println(hello_world.get());
}
}
}
可以看到结果 垃圾回收前后: 此时可以证明: 当内存不足时,会将软引用回收. 注意: 软引用回收指的是,只被软引用关联的对象,如果一个对象既有弱引用,又有强引用,那么是不会被回收的. ?
1.1.3 弱引用(WeakReference)
弱引用的回收比软引用要快,每次gc的时候都会回收,当然这里的回收也指的是只有弱引用的对象. 这意味着弱引用的生命周期只有一次垃圾回收的长度. 弱引用也有对应的实现类:
package java.lang.ref;
public class WeakReference<T> extends Reference<T> {
...
}
弱引用的回收证明例子:
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
public class WeakReferenceTest {
public static void main(String[] args) {
WeakReference weakReference =
new WeakReference<>(new String("hello world"));
System.out.println(weakReference.get());
System.gc();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("垃圾回收后");
System.out.println(weakReference.get());
}
}
结果证明:
1.1.4 虚引用(PhantomReference)
虚引用相比于软/弱引用来说回收的级别更高,也无法根据虚引用来获取对应的对象 对对象来说,有虚引用和没有虚引用是一样的,对对象的生命周期没有任何影响. 虚引用唯一的作用就是来作为对象回收的跟踪,当对象被回收的时候可以通知程序该对象被回收了,所以虚引用的创建必须要指定一个虚引用队列.
虚引用也有对应的实现类
package java.lang.ref;
import jdk.internal.vm.annotation.IntrinsicCandidate;
public class PhantomReference<T> extends Reference<T> {
...
}
可以通过代码验证虚引用的对象回收通知功能:
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
public class PhantomReferenceTest {
static ReferenceQueue referenceQueue = null;
public static class CheckGcThread extends Thread {
@Override
public void run() {
if (referenceQueue != null) {
Reference remove = null;
try {
remove = referenceQueue.remove();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (remove != null) {
System.out.println(remove+"对象被回收了");
}
}
}
}
public static void main(String[] args) {
CheckGcThread checkGcThread = new CheckGcThread();
checkGcThread.setDaemon(true);
checkGcThread.start();
referenceQueue = new ReferenceQueue();
PhantomReference hello_world = new PhantomReference(new String("hello" +
" world"), referenceQueue);
System.out.println(hello_world.get());
System.gc();
}
}
可以看到结果:
1.2 扩展
终结器引用: 用于调用对象的finalize方法,也是借助于队列的方式,一般情况用不到 对应实现类:
package java.lang.ref;
class FinalReference<T> extends Reference<T> {
...
}
|