作者:telami\
起源:www.telami.cn/2017/weak-reference/
Java 里一个对象 obj 被创立时,被放在堆里。当 GC 运行的时候,发现没有任何援用指向 obj,那么就会回收 obj 对象的堆内存空间。
换句话说,一个对象被回收, 必须满足两个条件:
(1)没有任何援用指向它
(2)GC 被运行。
在理论开发中,咱们能够通过把所有指向某个对象的 referece 置空来保障这个对象在下次 GC 运行的时候被回收,相似上面:
Object c = new Car();
c=null;
然而,这样做是一件很繁琐并且违反 GC 主动回收准则的事。对于简略的状况, 手动置空是不须要程序员来做的, 因为在 java 中, 对于简略对象, 当调用它的办法执行结束后, 指向它的援用会被从栈中弹出, 所以它就能在下一次 GC 执行时被回收了。
然而, 也有非凡例外. 当应用 cache 的时候, 因为 cache 的对象正是程序运行须要的, 那么只有程序正在运行, cache 中的援用就不会被 GC(或者说, cache 中的 reference 领有了和主程序一样的 life cycle). 那么随着 cache 中的 reference 越来越多, GC 无奈回收的 object 也越来越多, 无奈被主动回收。当这些 object 须要被回收时, 回收这些 object 的工作只有交给程序编写者了。然而这却违反了 GC 的实质 (主动回收能够回收的 objects)。
所以, java 中引入了 weak reference。
Object c = new Car(); // 只有 c 还指向 car object, car object 就不会被回收 -->(强援用)
当一个对象仅仅被 weak reference 指向, 而没有任何其余 strong reference 指向的时候, 如果 GC 运行, 那么这个对象就会被回收。
上面这个是网上的例子,首先定义一个实体类:
public class Car {
private double price;
private String color;
public Car(double price, String color)
{
this.price = price;
this.color = color;
}
public double getPrice()
{return price;}
public String getColor()
{return color;}
public String toString()
{return "This car is a" + this.color + "car, costs $" + price;}
}
个别应用 WeakReference 的时候都会定义一个类继承自 WeakReference,在这个类中再定义一些别的属性,这里就不定义别的属性了:
public class WeakReferenceCar extends WeakReference<Car>
{public WeakReferenceCar(Car car)
{super(car);
}
}
main 函数调用一下,当然为了更分明地看到 GC 的成果,设置虚拟机参数”-XX:+PrintGCDetails”:
public static void main(String[] args)
{Car car = new Car(2000.0, "red");
WeakReferenceCar wrc = new WeakReferenceCar(car);
wrc.setStr("111");
int i = 0;
while (true)
{if (wrc.get() != null)
{
i++;
System.out.println("WeakReferenceCar's Car is alive for "+ i +", loop - " + wrc);
}
else
{System.out.println("WeakReferenceCar's Car has bean collected");
break;
}
}
}
最初是运行后果
WeakReferenceCar's Car is alive for 68450, loop - interview.WeakReferenceCar@776ec8df
WeakReferenceCar's Car is alive for 68451, loop - interview.WeakReferenceCar@776ec8df
WeakReferenceCar's Car is alive for 68452, loop - interview.WeakReferenceCar@776ec8df
WeakReferenceCar's Car is alive for 68453, loop - interview.WeakReferenceCar@776ec8df
[GC (Allocation Failure) [PSYoungGen: 34304K->1000K(38400K)] 34320K->1016K(125952K), 0.0015129 secs] [Times: user=0.02 sys=0.02, real=0.00 secs]
WeakReferenceCar's Car is alive for 68454, loop - interview.WeakReferenceCar@776ec8df
WeakReferenceCar's Car has bean collected
Heap
PSYoungGen total 38400K, used 1986K [0x00000000d5e00000, 0x00000000da900000, 0x0000000100000000)
eden space 33280K, 2% used [0x00000000d5e00000,0x00000000d5ef6b70,0x00000000d7e80000)
from space 5120K, 19% used [0x00000000d7e80000,0x00000000d7f7a020,0x00000000d8380000)
to space 5120K, 0% used [0x00000000da400000,0x00000000da400000,0x00000000da900000)
ParOldGen total 87552K, used 16K [0x0000000081a00000, 0x0000000086f80000, 0x00000000d5e00000)
object space 87552K, 0% used [0x0000000081a00000,0x0000000081a04000,0x0000000086f80000)
Metaspace used 3547K, capacity 4564K, committed 4864K, reserved 1056768K
class space used 381K, capacity 388K, committed 512K, reserved 1048576K
能够看到在 68454 循环之后,WeakReferenceCar 关联的对象 Car 被回收掉了,留神是弱援用关联的对象 car 被回收,而不是弱援用自身 wrc 被回收。
WeakReference 的一个特点是它何时被回收是不可确定的, 因为这是由 GC 运行的不确定性所确定的. 所以, 个别用 weak reference 援用的对象是有价值被 cache, 而且很容易被从新被构建, 且很耗费内存的对象.
在 weak reference 指向的对象被回收后, weak reference 自身其实也就没有用了. java 提供了一个 ReferenceQueue 来保留这些所指向的对象曾经被回收的 reference. 用法是在定义 WeakReference 的时候将一个 ReferenceQueue 的对象作为参数传入构造函数.
近期热文举荐:
1.Java 15 正式公布,14 个新个性,刷新你的认知!!
2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!
3. 我用 Java 8 写了一段逻辑,共事直呼看不懂,你试试看。。
4. 吊打 Tomcat,Undertow 性能很炸!!
5.《Java 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!