- 浏览: 237910 次
- 性别:
- 来自: 上海
最新评论
-
weigeshikebi:
不得不赞一个
解惑 spring 嵌套事务 -
siemens800:
Mac OS X 10.7.2 的光盘还有挖,帅锅帮刻个盘发来 ...
MacBook 升级内存记 -
cry615:
帖子很不错,java里任何一个东西都是一门学问,很有很强的逻辑 ...
理解 Java 的 GC 与 幽灵引用 -
sharkka:
sogo1986 写道楼主举的例 ...
解惑 spring 嵌套事务 -
sogo1986:
楼主举的例子并没用体 ...
解惑 spring 嵌套事务
理解 Java 的 GC 与 幽灵引用
Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵),
这 4 种类型的引用与 GC 有着密切的关系, 让我们逐一来看它们的定义和使用场景 :
1. Strong Reference
StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收
@Test public void strongReference() { Object referent = new Object(); /** * 通过赋值创建 StrongReference */ Object strongReference = referent; assertSame(referent, strongReference); referent = null; System.gc(); /** * StrongReference 在 GC 后不会被回收 */ assertNotNull(strongReference); }
2. WeakReference & WeakHashMap
WeakReference, 顾名思义, 是一个弱引用, 当所引用的对象在 JVM 内不再有强引用时, GC 后 weak reference 将会被自动回收
@Test public void weakReference() { Object referent = new Object(); WeakReference<Object> weakRerference = new WeakReference<Object>(referent); assertSame(referent, weakRerference.get()); referent = null; System.gc(); /** * 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收 */ assertNull(weakRerference.get()); }
WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
@Test public void weakHashMap() throws InterruptedException { Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>(); Object key = new Object(); Object value = new Object(); weakHashMap.put(key, value); assertTrue(weakHashMap.containsValue(value)); key = null; System.gc(); /** * 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理 */ Thread.sleep(1000); /** * 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry */ assertFalse(weakHashMap.containsValue(value)); }
3. SoftReference
SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用
@Test public void softReference() { Object referent = new Object(); SoftReference<Object> softRerference = new SoftReference<Object>(referent); assertNotNull(softRerference.get()); referent = null; System.gc(); /** * soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用 */ assertNotNull(softRerference.get()); }
4. PhantomReference
作为本文主角, Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的 get() 方法永远返回 null, 这也正是它名字的由来
@Test public void phantomReferenceAlwaysNull() { Object referent = new Object(); PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>()); /** * phantom reference 的 get 方法永远返回 null */ assertNull(phantomReference.get()); }
诸位可能要问, 一个永远返回 null 的 reference 要来何用, 请注意构造 PhantomReference 时的第二个参数 ReferenceQueue(事实上 WeakReference & SoftReference 也可以有这个参数),
PhantomReference 唯一的用处就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中.
5. RererenceQueue
当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.
@Test public void referenceQueue() throws InterruptedException { Object referent = new Object(); ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>(); WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue); assertFalse(weakReference.isEnqueued()); Reference<? extends Object> polled = referenceQueue.poll(); assertNull(polled); referent = null; System.gc(); assertTrue(weakReference.isEnqueued()); Reference<? extends Object> removed = referenceQueue.remove(); assertNotNull(removed); }
6. PhantomReference vs WeakReference
PhantomReference 有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 Distributed GC, XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作).
其二, 它可以避免 finalization 带来的一些根本性问题, 上文提到 PhantomReference 的唯一作用就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中, 但是 WeakReference 也有对应的功能, 两者的区别到底在哪呢 ?
这就要说到 Object 的 finalize 方法, 此方法将在 gc 执行前被调用, 如果某个对象重载了 finalize 方法并故意在方法内创建本身的强引用, 这将导致这一轮的 GC 无法回收这个对象并有可能
引起任意次 GC, 最后的结果就是明明 JVM 内有很多 Garbage 却 OutOfMemory, 使用 PhantomReference 就可以避免这个问题, 因为 PhantomReference 是在 finalize 方法执行后回收的,也就意味着此时已经不可能拿到原来的引用, 也就不会出现上述问题, 当然这是一个很极端的例子, 一般不会出现.
7. 对比
taken from http://mindprod.com/jgloss/phantom.html
Soft vs Weak vs Phantom References
Type
Purpose
Use
When GCed
Implementing Class
Strong Reference
An ordinary reference. Keeps objects alive as long as they are referenced.
normal reference.
Any object not pointed to can be reclaimed.
default
Soft Reference
Keeps objects alive provided there’s enough memory.
to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key.
After a first gc pass, the JVM decides it still needs to reclaim more space.
java.lang.ref.SoftReference
Weak Reference
Keeps objects alive only while they’re in use (reachable) by clients.
Containers that automatically delete objects no longer in use.
After gc determines the object is only weakly reachable
java.lang.ref.WeakReference
java.util.WeakHashMap
Phantom Reference
Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize())
Special clean up processing
After finalization.
java.lang.ref.PhantomReference
8. 小结
一般的应用程序不会涉及到 Reference 编程, 但是了解这些知识会对理解 GC 的工作原理以及性能调优有一定帮助, 在实现一些基础性设施比如缓存时也可能会用到, 希望本文能有所帮助.
王政 于 2009,6,3
评论
把这个老帖子翻出来是因为今天一个同事看到 google-collections MapMaker 已经提供了类似功能
ConcurrentMap<Key, Graph> graphs = new MapMaker() .concurrencyLevel(32) .softKeys() .weakValues() .expiration(30, TimeUnit.MINUTES) .makeComputingMap( new Function<Key, Graph>() { public Graph apply(Key key) { return createExpensiveGraph(key); } });}
key 和 value 的 reference 类型以及 expiration strategy 都可以指定, 用起来很方便
thinking in java中介绍 对象的集合 时在介绍持有引用时提到了一些,但是很可惜,不是很详细。。。
深入java虚拟机 第二版 第9章 也有讲到
<div class="quote_div">
<p>ConcurrentHashMap<String, SoftReference><br>刚才自己捣鼓了一下,确实没有什么好办法可以保证当SoftReference被回收时,Key也自动被Remove.<br>觉得Memory Leak倒不是大问题,因为Key所占内存不多,最主要是Key过多会影响检索的效率.<br>个人觉得解决这个问题应该很简单:</p>
<p>我们使用SoftReference,必然要在获取SoftReference后需要检查SoftReference.get()是否为空,<span style="color: #ff0000;">如果为空,就只有一种可能,在你没有手动Remove的情况下,虚拟机把它回收了,那么回收必然造成有一些无效的key,在这种情况下做一次清理就可以了</span>。<br>注意<span style="color: #ff0000;">SoftReference.get()==null不应该<strong><span style="color: #0000ff;">平凡</span></strong>出现</span>,除非虚拟机<span style="color: #0000ff;"><strong>平凡</strong></span>对SoftReference进行回收,如果这样,你或许要检查你程序了。</p>
<p>另外通过继承ConcurrentHashMap 重写put/get几个方法,应该可以把这些操作封装到子类中,还是让子类作为一个Map<K, T>来使用。</p>
<p>感觉直接使用ConcurrentHashMap<String, SoftReference>还是别扭。</p>
<p> </p>
</div>
<p>楼主,打拼音的吧。</p>
<p> </p>
<pre name="code" class="java">import static org.junit.Assert.*;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import org.junit.Test;
public class TestCase {
@Test
public void testWakeConcurrentMap() {
ReferenceMap wakeMap = new ReferenceMap(WeakReference.class);
String key = "abc";
Object value = new Object();
wakeMap.put(key, value);
value = null;
System.gc();
assertNull(wakeMap.get(key));
assertTrue(wakeMap.isEmpty());
}
@Test
public void testSoftConcurrentMap() {
ReferenceMap wakeMap = new ReferenceMap(SoftReference.class);
String key = "abc";
Object value = new Object();
wakeMap.put(key, value);
value = null;
System.gc();
assertNotNull(wakeMap.get(key));
assertFalse(wakeMap.isEmpty());
}
}
</pre>
<p> </p>
<p>下面是Concurrent的Map子类</p>
<pre name="code" class="java">import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
public class ReferenceMap extends ConcurrentHashMap {
private Class<? extends Reference> refClass;
public ReferenceMap(Class refClass) {
super();
this.refClass = refClass;
}
public Object put(Object key, Object value) {
Reference ref = null;
//这里有点尴尬,没有默认构造器,无法使用反射获得实例...
if (refClass == SoftReference.class) {
ref = new SoftReference(value);
} else if (refClass == WeakReference.class) {
ref = new WeakReference(value);
}
Reference result = (Reference) super.put(key, ref);
if (result != null) {
return result.get();
} else
return null;
}
@Override
public Object get(Object key) {
Reference ref = (Reference) super.get(key);
if (ref.get() == null) {
cleanOverdueKeys();
return null;
}
return ref.get();
}
@Override
public boolean containsKey(Object key) {
if (super.containsKey(key)) {
Reference ref = (Reference) super.get(key);
if (ref.get() == null) {
return false;
} else
return true;
} else
return false;
}
//清除那些没用的key
private void cleanOverdueKeys() {
ArrayList removeList = new ArrayList();
for (Object key : this.keySet()) {
if (!containsKey(key))
removeList.add(key);
}
for (Object key : removeList) {
this.remove(key);
}
}
}
</pre>
<p>我们使用SoftReference,必然要在获取SoftReference后需要检查SoftReference.get()是否为空,<span style="color: #ff0000;">如果为空,就只有一种可能,在你没有手动Remove的情况下,虚拟机把它回收了,那么回收必然造成有一些无效的key,在这种情况下做一次清理就可以了</span>。<br>注意<span style="color: #ff0000;">SoftReference.get()==null不应该频繁出现</span>,除非虚拟机频繁对SoftReference进行回收,如果这样,你或许要检查你程序了。</p>
<p>另外通过继承ConcurrentHashMap 重写put/get几个方法,应该可以把这些操作封装到子类中,还是让子类作为一个Map<K, T>来使用。</p>
<p>感觉直接使用ConcurrentHashMap<String, SoftReference>还是别扭。</p>
<p> </p>
thinking in java中介绍 对象的集合 时在介绍持有引用时提到了一些,但是很可惜,不是很详细。。。
<div class="quote_div">我还没看后面,第一个例子就是错的!
<p>而且这个例子的错误好几处,lz根本就没搞明白堆内存,栈内存以及引用和对象的关系这几个问题。</p>
<p>Object strongReference = referent;现在这俩ref都指向了new Object();产生的对象;</p>
<p>referent = null;lz认为这样strongReference 也会是null了????</p>
<p>System.gc();如果你明白什么是分代式回收以及图检索策略,就该明白这里是否会回收上面产生的对象!</p>
<p>这俩ref一直都在生命周期内,为什么要回收这个对象呢?</p>
<p>后面还没看,我03年的时候曾经仔细看过这四种ref的关系,但是除了高速缓存可能会用弱引用外,其他地方似乎很难用到啊。</p>
<p> </p>
<p> </p>
<p> </p>
<p><br></p>
<p> </p>
<p>理解 Java 的 GC 与 幽灵引用<br> <br> Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵), <br>这 4 种类型的引用与 GC 有着密切的关系, 让我们逐一来看它们的定义和使用场景 :<br><br> 1. Strong Reference<br> <br> StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收</p>
<pre name="code" class="java"> @Test
public void strongReference() {
Object referent = new Object();
/**
* 通过赋值创建 StrongReference
*/
Object strongReference = referent;
assertSame(referent, strongReference);
referent = null;
System.gc();
/**
* StrongReference 在 GC 后不会被回收
*/
assertNotNull(strongReference);
}
</pre>
<p><br><br><br><br> 2. WeakReference & WeakHashMap<br><br>WeakReference, 顾名思义, 是一个弱引用, 当所引用的对象在 JVM 内不再有强引用时, GC 后 weak reference 将会被自动回收</p>
<pre name="code" class="java"> @Test
public void weakReference() {
Object referent = new Object();
WeakReference<Object> weakRerference = new WeakReference<Object>(referent);
assertSame(referent, weakRerference.get());
referent = null;
System.gc();
/**
* 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收
*/
assertNull(weakRerference.get());
}
</pre>
<p><br><br><br>WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry</p>
<pre name="code" class="java"> @Test
public void weakHashMap() throws InterruptedException {
Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
Object key = new Object();
Object value = new Object();
weakHashMap.put(key, value);
assertTrue(weakHashMap.containsValue(value));
key = null;
System.gc();
/**
* 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理
*/
Thread.sleep(1000);
/**
* 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
*/
assertFalse(weakHashMap.containsValue(value));
}
</pre>
<p><br><br><br> 3. SoftReference<br><br>SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用</p>
<pre name="code" class="java"> @Test
public void softReference() {
Object referent = new Object();
SoftReference<Object> softRerference = new SoftReference<Object>(referent);
assertNotNull(softRerference.get());
referent = null;
System.gc();
/**
* soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用
*/
assertNotNull(softRerference.get());
}
</pre>
<p><br><br><br> 4. PhantomReference<br><br> 作为本文主角, Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的 get() 方法永远返回 null, 这也正是它名字的由来</p>
<pre name="code" class="java"> @Test
public void phantomReferenceAlwaysNull() {
Object referent = new Object();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());
/**
* phantom reference 的 get 方法永远返回 null
*/
assertNull(phantomReference.get());
}
</pre>
<p><br><br> 诸位可能要问, 一个永远返回 null 的 reference 要来何用, 请注意构造 PhantomReference 时的第二个参数 ReferenceQueue(事实上 WeakReference & SoftReference 也可以有这个参数),<br>PhantomReference 唯一的用处就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中.<br><br> 5. RererenceQueue<br><br>当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.</p>
<pre name="code" class="java"> @Test
public void referenceQueue() throws InterruptedException {
Object referent = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue);
assertFalse(weakReference.isEnqueued());
Reference<? extends Object> polled = referenceQueue.poll();
assertNull(polled);
referent = null;
System.gc();
assertTrue(weakReference.isEnqueued());
Reference<? extends Object> removed = referenceQueue.remove();
assertNotNull(removed);
}
</pre>
<p><br><br>6. PhantomReference vs WeakReference<br><br>PhantomReference 有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 Distributed GC, XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作). <br><br>其二, 它可以避免 finalization 带来的一些根本性问题, 上文提到 PhantomReference 的唯一作用就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中, 但是 WeakReference 也有对应的功能, 两者的区别到底在哪呢 ?<br>这就要说到 Object 的 finalize 方法, 此方法将在 gc 执行前被调用, 如果某个对象重载了 finalize 方法并故意在方法内创建本身的强引用, 这将导致这一轮的 GC 无法回收这个对象并有可能<br>引起任意次 GC, 最后的结果就是明明 JVM 内有很多 Garbage 却 OutOfMemory, 使用 PhantomReference 就可以避免这个问题, 因为 PhantomReference 是在 finalize 方法执行后回收的,也就意味着此时已经不可能拿到原来的引用, 也就不会出现上述问题, 当然这是一个很极端的例子, 一般不会出现. <br><br>7. 对比<br><br>taken from http://mindprod.com/jgloss/phantom.html</p>
<p><span style="font-family: 'tiresias pcfont z'; color: #421f00; font-size: 16px;">
<table class="standard" border="0">
<thead>
<tr>
<th style="font-family: calibri, 'bitstream vera sans', 'segoe ui', arial, helvetica, sans-serif; background-color: #95cbff; color: #000000; display: table-cell; font-size: 1.08em; font-weight: bold; padding: 5px;" colspan="5">Soft vs Weak vs Phantom References</th>
</tr>
<tr>
<th style="font-family: calibri, 'bitstream vera sans', 'segoe ui', arial, helvetica, sans-serif; background-color: #95cbff; color: #000000; display: table-cell; font-size: 1.08em; font-weight: bold; padding: 5px;">Type</th>
<th style="font-family: calibri, 'bitstream vera sans', 'segoe ui', arial, helvetica, sans-serif; background-color: #95cbff; color: #000000; display: table-cell; font-size: 1.08em; font-weight: bold; padding: 5px;">Purpose</th>
<th style="font-family: calibri, 'bitstream vera sans', 'segoe ui', arial, helvetica, sans-serif; background-color: #95cbff; color: #000000; display: table-cell; font-size: 1.08em; font-weight: bold; padding: 5px;">Use</th>
<th style="font-family: calibri, 'bitstream vera sans', 'segoe ui', arial, helvetica, sans-serif; background-color: #95cbff; color: #000000; display: table-cell; font-size: 1.08em; font-weight: bold; padding: 5px;">When GCed</th>
<th style="font-family: calibri, 'bitstream vera sans', 'segoe ui', arial, helvetica, sans-serif; background-color: #95cbff; color: #000000; display: table-cell; font-size: 1.08em; font-weight: bold; padding: 5px;">Implementing Class</th>
</tr>
</thead>
<tbody>
<tr>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Strong Reference</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">An ordinary reference. Keeps objects alive as long as they are referenced.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">normal reference.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Any object not pointed to can be reclaimed.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">default</td>
</tr>
<tr>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Soft Reference</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Keeps objects alive provided there’s enough memory.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">After a first gc pass, the JVM decides it still needs to reclaim more space.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">
<span class="package">java.lang.ref.</span><span class="class" style="background-color: transparent; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Lucida Console', 'Lucida Sans', 'Lucida Sans Unicode', Courier, 'Courier New', 'Segoe UI', Arial, monospace; color: #653510;">SoftReference</span> </td>
</tr>
<tr>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Weak Reference</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Keeps objects alive only while they’re in use (reachable) by clients.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Containers that automatically delete objects no longer in use.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">After gc determines the object is only weakly reachable</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">
<span class="package">java.lang.ref.</span><span class="class" style="background-color: transparent; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Lucida Console', 'Lucida Sans', 'Lucida Sans Unicode', Courier, 'Courier New', 'Segoe UI', Arial, monospace; color: #653510;">WeakReference</span> <br><span class="package">java.util.</span><span class="class" style="background-color: transparent; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Lucida Console', 'Lucida Sans', 'Lucida Sans Unicode', Courier, 'Courier New', 'Segoe UI', Arial, monospace; color: #653510;">WeakHashMap</span> </td>
</tr>
<tr>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Phantom Reference</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use of<span class="method">finalize</span>())</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">Special clean up processing</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">After finalization.</td>
<td style="font-size: 1em; line-height: 1.2em; padding: 5px;">
<span class="package">java.lang.ref.</span><span class="class" style="background-color: transparent; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Lucida Console', 'Lucida Sans', 'Lucida Sans Unicode', Courier, 'Courier New', 'Segoe UI', Arial, monospace; color: #653510;">PhantomReference<br><br></span>
</td>
</tr>
</tbody>
</table></span><br>8. 小结<br> 一般的应用程序不会涉及到 Reference 编程, 但是了解这些知识会对理解 GC 的工作原理以及性能调优有一定帮助, 在实现一些基础性设施比如缓存时也可能会用到, 希望本文能有所帮助.<br><br> 王政 于 2009,6,3</p>
<p> </p>
</div>
<p> </p>
http://zhang-xzhi-xjtu.iteye.com/blog/413159
当垃圾收集时一定会被当垃圾清除,不管这个对象是否还被其他引用???
应该是这样 如果你Sofrreference里面引用的对象没有别的引用的时候 在每次内存溢出前就会被自动清理掉
Object -> SoftReference -> Map
SoftReference对Object的引用会自动断开。但是SoftReference本身还会在Map中存在一个Entry。如何做到内存溢出的时候自动把SoftReference从Map中移除呢?
你用softReference来做缓存主要目的是为了长期持有对象而不引起内存泄露 那个对象自然就是被softReference引用的
既然在内存泄露前 你的大对象已经被清理了 你的这次危机自然就解除了 等你下一次用这个大对象的时候 你会发现softReference的get()是null了 那么你是不是会重新put一个新的进去呢
于是你上次的softReference会在下次gc调用的时候被清理掉了...
如果这个key再也不被引用了,就永远不会被清除了。这算不算是Memory Leak呢?
针对以上各位说的问题,对于Map当中的key,可以做一个简单的修改,代码如下:
先有一个工具类,专用于获得key值的。
public class ToolUtil {
//作为缓存的Map
public static final ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();
public static ExpandSoftReference getKey(String key){
return new ExpandSoftReference(new ExpandSring(key));
}
private static class ExpandSring{
private String key;
private ExpandSring() {
}
private ExpandSring(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
protected void finalize() throws Throwable {
super.finalize();
concurrentHashMap.remove(new ExpandSoftReference(this));
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExpandSring that = (ExpandSring) o;
if (key != null ? !key.equals(that.key) : that.key != null) return false;
return true;
}
public int hashCode() {
return (key != null ? key.hashCode() : 0);
}
}
}
ExpandSoftReference类内容如下:
public class ExpandSoftReference extends SoftReference {
private String relativelyStr;
public ExpandSoftReference(Object referent) {
super(referent);
relativelyStr = referent.toString()+"_key";
}
public ExpandSoftReference(Object referent, ReferenceQueue q) {
super(referent, q);
relativelyStr = referent.toString()+"_key";
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExpandSoftReference that = (ExpandSoftReference) o;
if (relativelyStr != null ? !relativelyStr.equals(that.relativelyStr) : that.relativelyStr != null)
return false;
return true;
}
public int hashCode() {
return (relativelyStr != null ? relativelyStr.hashCode() : 0);
}
}
我在使用时如下这样,便可以了
ToolUtil.concurrentHashMap.put(ToolUtil.getKey("snsky"),new Object());
此扩展有以下几个关键点所在
ExpandSring类扩展了
finalize方法
在ExpandSring类对象占用的内存被回收之前释放在Map当中对应key-value对
ExpandSoftReference类扩展了"软引用类"(SoftReference)
并且为了可以跟据key值查找到对应的value
此类当中用relativelyStr属性作为比较的值。在获取方法时可以用
ToolUtil.concurrentHashMap.get(ToolUtil.getKey("snsky"));
以上代表我个人的一些想法,希望能集思广义,看是否有不合理的地方。
应该是这样 如果你Sofrreference里面引用的对象没有别的引用的时候 在每次内存溢出前就会被自动清理掉
Object -> SoftReference -> Map
SoftReference对Object的引用会自动断开。但是SoftReference本身还会在Map中存在一个Entry。如何做到内存溢出的时候自动把SoftReference从Map中移除呢?
你用softReference来做缓存主要目的是为了长期持有对象而不引起内存泄露 那个对象自然就是被softReference引用的
既然在内存泄露前 你的大对象已经被清理了 你的这次危机自然就解除了 等你下一次用这个大对象的时候 你会发现softReference的get()是null了 那么你是不是会重新put一个新的进去呢
于是你上次的softReference会在下次gc调用的时候被清理掉了...
如果这个key再也不被引用了,就永远不会被清除了。这算不算是Memory Leak呢?
不被清除的对象未必都是Memory Leak。
一般来说,缓存或者静态数据应该是贯穿整个application的生命周期(假设没有任何的缓存策略),此时key是被有意识的引用或者说是保存:Map(global or static)-Entry-Key。所以对于缓存中所有的数据,可不能说,用不到的就是Memory Leak。正如湖人打魔术,奥兰多混好了,就不回洛杉矶了,可洛杉矶的场馆咱照样得维护好了~~
public void weakReference() {
Object referent = new Object();
WeakReference<Object> weakRerference = new WeakReference<Object>(referent);
assertSame(referent, weakRerference.get());
referent = null;
System.gc();
/**
* 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收
*/
assertNull(weakRerference.get());
和
public void softReference() {
Object referent = new Object();
SoftReference<Object> softRerference = new SoftReference<Object>(referent);
assertNotNull(softRerference.get());
referent = null;
System.gc();
/**
* soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用
*/
assertNotNull(softRerference.get());
}
代码差不多,只是SoftReference和WeakReference不同,引用效果就不同,能不能具体举例一下哪些是SoftReference,哪些是WeakReference
发表评论
-
Bookmarks
2010-07-07 16:42 1484Architecture J2EE cluster htt ... -
XML validation error on request: cvc-complex-type
2010-04-15 21:45 1335see http://72.5.124.102/threa ... -
Spring LoadTimeWeaver 的那些事儿
2009-10-05 00:39 3985DDD 现在越来越流行了, 不管正确与否, new U ... -
基于 Apache Mina 的 RPC 实现 (长连接 webservice)
2008-11-27 23:26 4345写了一个基于 Apache Mina 和 SpringRemo ... -
Atomikos JTA for Hibernate3
2007-11-22 14:52 3318http://wiki.atomikos.org/bin/vi ... -
Spring AOP 概览与细节
2007-08-05 03:21 5936@王政 @2007-08-04 @转载请注明 ... -
解惑 spring 嵌套事务
2006-11-25 01:03 36024解惑 spring 嵌套事务 /** * @au ... -
使用 FactoryBean 让你的 spring 配置动起来
2006-11-01 17:43 10456看到不少朋友讨论 spring 配置时认为 spring 配置 ... -
一个可能的列级权限控制方案讨论
2006-05-25 18:45 17931最近的项目需要做到列级权限控制, 大意如下 publi ... -
Spring 事务简化配置
2006-03-21 00:33 36708在 spring 中, 事务管理一般是通过声明一个 txPr ... -
再论 Acegi 权限存储策略
2006-02-18 00:17 12774本文原出处 http://starcraft.blogdriv ... -
以前写的一篇介绍 Acegi 的文档
2006-01-05 09:51 13261半年前写的, 版本是 0.8.3, 主要是翻译了一些 ref ... -
Acegi 资源配置动态扩展实现
2005-12-13 16:21 19156本文原出处 : http://starcr ...
相关推荐
Java GC与性能调优文档 作者:高飞
一般的应用程序不会涉及到 Reference 编程, 但是了解这些知识会对理解 GC 的工作原理以及性能调优有一定帮助,在实现一些基础性设施比如缓存时也可能会用到,希望本文能有所帮助
GC java 手册 kindle格式 GC java 手册 kindle格式 GC java 手册 kindle格式
让你对java gc 的工作原理有更深的了解 谢谢下载
NULL 博文链接:https://wangwengcn.iteye.com/blog/1606192
GChisto及CMS GC相应补丁文件,补丁文件未亲测。 This patch adds the following features and improvements when using CMS GC in incremental mode: detecting Full GCs corrected parsing errors when using -XX:...
Java基础[Java基础]--Java GC工作原理
成为JavaGC专家PartII—如何监控Java垃圾回收机制Java开发Java经验技巧共12页.pdf.zip
《深入理解JVM & G1 GC》主要为学习Java语言的学生、初级程序员提供GC的使用参考建议及经验,着重介绍了G1 GC。中国的软件开发行业已经有几十年了,从目前的行业发展来看,单纯的软件公司很难有发展,目前流 资源太...
Java SE编程入门教程 java GC(共6页).pptx Java SE编程入门教程 java instanceof(共3页).pptx Java SE编程入门教程 java IO(共28页).pptx Java SE编程入门教程 java Math(共11页).pptx Java SE编程入门教程 ...
深入理解java虚拟机视频教程,jvm原理,java虚拟机,jvm性能调优,内存模型,gc工作原理,内存分配,类的加载等等视频教程
jvm配置参数详解,以及Java gc详解
Java GC的副本.pptx
在第一篇文章成为JavaGC专家PartI—深入浅出Java垃圾回收机制中我们学习了不同GC算法的执行过程,GC如何工作,新生代及老年代的基本概念,在JDK7中你应该了解的5种GC类型以及他们的性能如何。在第二篇文章成为JavaGC...
NULL 博文链接:https://seanzhou.iteye.com/blog/2003941
一篇文章教你深入理解Java垃圾收集(GC)机制
JVM内存管理的介绍,编写GC友好的代码。 本材料主要关心 Sun Hotspot JVM 6的内存管理 Sun Hotspot JVM 6的GC模型 主要针对JVM6的GC模型,但也会简单介绍Java 7的G1 编写GC友好代码的一些技巧
白话说java gc垃圾回收.docx
1、 强引, 只要引存在,垃圾回收器永远不会回收 2、 软引,必须引,内存溢出之前进回收,可以通过以下代码实现 3、 弱引,第次垃圾回收时回收,可以通过如下代码