java学习记录强引用、软引用、弱引用、虚引用

编程

当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题(无论何时都不会回收)

public static void main(String[] args) {

List list = new ArrayList<>();

int i = 1;

while (i++ < Integer.MAX_VALUE) {

list.add("ssssss");

}

System.out.println("-------end-------");

}

2.软引用 (SoftReference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存(内存不足时候回收)

当内存足够的时候不会被回收,所以能正常输出对象的地址

public static void main(String[] args) {

// 定义一个软引用

SoftReference<byte[]> soft = new SoftReference<byte[]>(new byte[1024 * 1024 * 1024]);

// 消耗内存

for(int i = 0; i < 10;i++) {

byte[] buff = new byte[1024 * 1024];

}

// 建议执行GC

System.gc();

// 打印结果

System.out.println(soft.get());

}

下面我们把内存使用再 扩大1024倍, 当内存不够的时候,GC回收了内存,所以输出的内存地址就为null

public static void main(String[] args) {

// 定义一个软引用

SoftReference<byte[]> soft = new SoftReference<byte[]>(new byte[1024 * 1024 * 1024]);

// 消耗内存

for(int i = 0; i < 10;i++) {

byte[] buff = new byte[1024 * 1024 * 1024];

}

// 建议执行GC

System.gc();

// 打印结果

System.out.println(soft.get());

}

3.弱引用(WeakReference)

只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它的内存区域,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存(无论内存足不足都回收)

下面就是一个弱引用的例子,这个是软引用内存足够情况下的那个例子直接改成弱引用而来,证明:证明了即使是内存足够的情况下,只要执行了GC,就一定会回收弱引用

public static void main(String[] args) {

// 定义一个弱引用

WeakReference<byte[]> weak = new WeakReference<byte[]>(new byte[1024 * 1024 * 1024]);

// 消耗内存

for(int i = 0; i < 10;i++) {

byte[] buff = new byte[1024 * 1024];

}

// 建议执行GC

System.gc();

// 打印结果

System.out.println(weak.get());

}

这里面也可以看出一个问题,就是执行到一半的时候,GC突然回收了我们的弱引用类型,导致无法正常完成,但是由于GC的线程优先级比一般线程的优先级都要低,保证在我们使用完对象之后再回收,使我们的系统更加稳定

4.虚引用(PhantomReference)

虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,不过虚引用的作用不是为了我们使用对象,而是为了记录。

为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知

因为虚引用的对象我们是使用不到的,它的get()始终返回一个null

public T get() {

return null;

}

创建虚引用的时候需要传入1个引用对象,和一个引用队列,当该虚引用对象被回收之后,不会马上销毁,而会将这个虚引用加入引用队列

public PhantomReference(T referent, ReferenceQueue<? super T> q) {

super(referent, q);

}

我们再看看下面的例子

public static void main(String[] args) {

// 定义一个引用队列

ReferenceQueue<byte[]> queue = new ReferenceQueue<byte[]>();

// 定义一个软引用类型

PhantomReference<byte[]> phantom = new PhantomReference<byte[]>(new byte[1024 * 1024],queue);

// 第一次打印,这个时候还没执行内存回收,所以队列里面是null

System.out.println(queue.poll());

// 消耗内存

for(int i = 0; i < 10;i++) {

byte[] buff2 = new byte[1024 * 1024 * 1024];

}

// 建议执行GC

System.gc();

// 如果对象被回收,则会放进队列

System.out.println(queue.poll());

}

注意:以上所有例子的System.gc(); 并不是执行GC的语句,而是建议jvm执行GC,并不是执行了System.gc(); 就100%执行内存回收

高并发情况下会把我们内存撑爆,因为我们的对象引用由栈内存指向堆内存且我们经常使用的是强引用,如果栈内存同时存在太多强引用的时候,栈内存没来得及释放,强引用过多一直存在导致GC无法回收内存,这个时候就会使我们系统出现OOM。如果设计好线程数量使栈内不会有过多引用,合理释放掉栈内存引用,这个时候堆内存没有引用的情况下,则会回收掉,避免了高并发导致的OOM

以上是 java学习记录强引用、软引用、弱引用、虚引用 的全部内容, 来源链接: utcz.com/z/513812.html

回到顶部