咨询热线:13613863834 联系人:龙伦光 地址:宁夏自治省银川市西夏区怡祥新村27号楼2单元202
Java 弱引用
来源:宝马会最新网站 发布时间:2019-11-22 点击量:223
定义
弱引用是使用WeakReference创建的引用,弱引用也是用来描述非必需对象的,它是比软引用更弱的引用类型。在发生GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收。
说明
弱引用,从名字来看就很弱嘛,这种引用指向的对象,一旦在GC时被扫描到,就逃脱不了被回收的命运。
但是,弱引用指向的对象也并不一定就马上会被回收,如果弱引用对象较大,直接进到了老年代,那么就可以苟且偷生到Full GC触发前,所以弱引用对象也可能存在较长的一段时间。一旦一个弱引用对象被垃圾回收器回收,便会加入到一个引用队列中(如果有的话)。
弱引用对应的类为WeakReference,举个栗子:
String s = new String("Frank"); WeakReference<String> weakRef = new WeakReference<String>(s);s = null;
这里我们把s设置为null后,字符串对象便只有弱引用指向它。
弱可达如果一个对象与GC Roots之间仅存在弱引用,则称这个对象为弱可达(weakly reachable)
对象。
注意在垃圾回收器回收一个对象前,WeakReference类所提供的get方法会返回其引用对象的强引用,一旦垃圾回收器回收掉该对象之后,get方法将返回null。所以在获取弱引用对象的代码中,一定要判断是否为null,以免出现NullPointerException异常导致应用崩溃。
下面的代码会让s再次持有对象的强引用:
s = weakRef.get();
如果在weakRef包裹的对象被回收前,用强引用关联该对象,那这个对象又会变成强可达状态。
来看一个简单的栗子了解一下WeakReference引用的对象是何时被回收的:
public class WeakReferenceTest { private static final List<Object> TEST_DATA = new LinkedList<>(); private static final ReferenceQueue<TestClass> QUEUE = new ReferenceQueue<>(); public static void main(String[] args) { TestClass obj = new TestClass("Test"); WeakReference<TestClass> weakRef = new WeakReference<>(obj, QUEUE); //可以重新获得OOMClass对象,并用一个强引用指向它 //oomObj = weakRef.get(); // 该线程不断读取这个弱引用,并不断往列表里插入数据,以促使系统早点进行GC new Thread(() -> { while (true) { TEST_DATA.add(new byte[1024 * 100]); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } System.out.println(weakRef.get()); } }).start(); // 这个线程不断读取引用队列,当弱引用指向的对象呗回收时,该引用就会被加入到引用队列中 new Thread(() -> { while (true) { Reference<? extends TestClass> poll = QUEUE.poll(); if (poll != null) { System.out.println("--- 弱引用对象被jvm回收了 ---- " + poll); System.out.println("--- 回收对象 ---- " + poll.get()); } } }).start(); //将强引用指向空指针 那么此时只有一个弱引用指向TestClass对象 obj = null; try { Thread.currentThread().join(); } catch (InterruptedException e) { e.printStackTrace(); System.exit(1); } } static class TestClass { private String name; public TestClass(String name) { this.name = name; } @Override public String toString() { return "TestClass - " + name; } }}
设置一下虚拟机参数:
-verbose:gc -Xms4m -Xmx4m -Xmn2m
运行结果如下:
[GC (Allocation Failure) 1017K->464K(3584K), 0.0014345 secs][GC (Allocation Failure) 1483K->536K(3584K), 0.0017221 secs][GC (Allocation Failure) 1560K->648K(3584K), 0.0036572 secs]TestClass - TestTestClass - TestTestClass - Test[GC (Allocation Failure) 1621K->984K(3584K), 0.0011455 secs]--- 弱引用对象被jvm回收了 ---- java.lang.ref.WeakReference@51a947fe--- 回收对象 ---- nullnull...省略n个null和几次GC信息[Full GC (Ergonomics) 2964K->2964K(3584K), 0.0025450 secs][Full GC (Allocation Failure) 2964K->2964K(3584K), 0.0021907 secs]java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid6860.hprof ...Heap dump file created [3912229 bytes in 0.011 secs]Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space at weakhashmap.WeakReferenceTest.lambda$main$0(WeakReferenceTest.java:22) at weakhashmap.WeakReferenceTest$$Lambda$1/764977973.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)
可以看到,其实弱引用也并不是一发生GC就被回收掉了。
应用场景
如果一个对象仅仅是偶尔使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用 WeakReference 来引用该对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
一般来说,很少直接使用WeakReference,而是使用WeakHashMap。在WeakHashMap中,内部有一个引用队列,插入的元素会被包裹成WeakReference,并加入队列中,用来做缓存再合适不过。
在Tomcat的缓存中,其实就用到了WeakHashMap:
public final class ConcurrentCache<K,V> { private final int size; private final Map<K,V> eden; private final Map<K,V> longterm; public ConcurrentCache(int size) { this.size = size; this.eden = new ConcurrentHashMap<>(size); this.longterm = new WeakHashMap<>(size); } public V get(K k) { // 先从eden中取 V v = this.eden.get(k); if (v == null) { // 如果取不到再从longterm中取 synchronized (longterm) { v = this.longterm.get(k); } // 如果取到则重新放到eden中 if (v != null) { this.eden.put(k, v); } } return v; } public void put(K k, V v) { if (this.eden.size() >= size) { // 如果eden中的元素数量大于指定容量,将所有元素放到longterm中 synchronized (longterm) { this.longterm.putAll(this.eden); } this.eden.clear(); } this.eden.put(k, v); }}
这里有eden和longterm的两个map,如果对jvm堆了解的话,可以看出tomcat在这里是使用ConcurrentHashMap和WeakHashMap做了类似分代缓存的操作。
在put方法里,在插入键值对时,先检查eden缓存的容量是否超出设定的大小。如果没有则直接放入eden缓存,如果超了则锁定longterm将eden中所有的键值对都放入longterm。再将eden清空并插入该键值对。
在get方法中,也是优先从eden中找对应的key,如果没有则进入longterm缓存中查找,找到后就加入eden缓存并返回。
经过这样的设计,相对常用的对象都能在eden缓存中找到,不常用(有可能被销毁的对象)的则进入longterm缓存。而longterm的key的实际对象没有其他引用指向它时,gc就会自动回收heap中该弱引用指向的实际对象,并将弱引用放入其引用队列中。
弱引用与软引用对比
弱引用与软引用的区别在于:
- 只具有弱引用的对象拥有更短暂的生命周期。被垃圾回收器回收的时机不一样,在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。而被软引用关联的对象只有在内存不足时才会被回收。弱引用不会影响GC,而软引用会一定程度上对GC造成影响。
相似之处:都是用来描述非必需对象的。
那么什么时候用SoftReference,什么时候用WeakReference呢?
如果缓存的对象是比较大的对象,使用频率相对较高的对象,那么使用SoftReference会更好,因为这样能让缓存对象有更长的生命周期。
如果缓存对象都是比较小的对象,使用频率一般或者相对较低,那么使用WeakReference会更合适。
当然,如果实在不知道选哪个,一般而言,用作缓存时使用WeakHashMap都不会有太大问题。
小结
弱引用是比软引用更弱的引用类型弱引用不能延长对象的生命周期,一旦对象只剩下弱引用,它就随时可能会被回收可以通过弱引用获取对象的强引用弱引用适合用作缓存相关产品
-
赵锡军表示,随着食用农产品价格回落,预计3月份物价涨幅将有所收窄,但对于物价上涨压力还是要密切关注,并且做好应对的准备。(完)
-
-
4月22日,中国传媒大学成立雄安新区发展研究院,并举行首届雄安新区发展研讨会。该校雄安新区发展研究院首任院长由经管学部学部长兼文化发展研究院院长范周担任,将研究文化、区域经济、社会管理等六个领域。
-
不可否认,合资自主在一定程度上下延了老款合资产品的价格区间,开拓了比较大的市场空间,但相对比较老旧的产品又制约了其发展。上下受限制的合资自主,出路只有两条:或是加快技术迭代,但这会和合资产品产生冲突;或是偏安一隅。显然,无论是前者还是后者,都是各车企不愿意看到的,而问题的根源在于对合资自主的定义不够准确。
-
中新网5月23日电 据台湾东森电视台网站报道,马英九日前前往台湾灾害应变中心视察,连日来台湾方面与菲律宾关系紧张,加之大雨来袭来袭,在“内忧外患”操劳之下,简报过程中竟频频打盹。马英九办公室发言人李佳霏好心写小纸条提醒马英九“媒体在拍您打瞌睡”,马英九看了立即惊醒,吓得不敢再睡。
-
评论说,两岸和平进展至今,经贸往来密切,台湾经济仰赖大陆之深众人皆知。台湾到底该把大陆当作“假想敌”,还是把两岸关系搞好,把大陆当成“兄弟”,避免战争?答案其实显而易见。
-
四是在原审有关重要证据缺失的情况下,充分运用了“常理”这个重要的裁判理念。再审判决在评判本案原办案人员当年的行为和事后的解释时多次使用了“不合常理”这一表述,具有重要导向作用。这里的常理,就是普通老百姓都懂得、普遍认同的道理,就是人民群众的公平正义观,人民法院在作出裁判时,应当考量人民群众的公平正义观。
-
当然,车位月租较高只是普遍情况,如果不怕远,在五羊新城也能租到一些相对便宜一些的车位,并且不用是小区的业主。珠江宾馆的有关负责人介绍,目前有月租800元的车位出租。据称,珠江宾馆目前还有600个左右车位在改造中,不久还会有300个车位供应,车位供应较为充足。
热点资讯
- 前副总经理行贿广福药业也被判“单位受贿”,罚款600000元,副总经理Sina财经2019-10-29
- 我们收到了VERTU新机发布会邀请函:奢侈手机大佬重磅回归2019-07-17
- 攻克电池生产难题:特斯拉Model3每周5000辆产量将很快实现2019-07-17
- 全球首富贝索斯给儿女们的忠告:为后天的选择骄傲而不是天赋2019-11-05
- 任正非:“请你们不要再吹捧华为了”2019-11-08
- 英特尔官方确认:第九代酷睿处理器支持128GBDDR4内存2019-11-17
- 暴风集团控股股东冯鑫部分股份被司法冻结2019-11-06
- 发扬社会主义核心价值观的艺术家李学健荣获新浪财经改革先锋称号。2019-11-16