答案 0 :(得分:3)
我终于完成了检查Hotspot JVM源代码并找到了以下代码。
在referenceProcessor.cpp中:
void ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
// Stop treating discovered references specially.
disable_discovery();
bool trace_time = PrintGCDetails && PrintReferenceGC;
// Soft references
{
TraceTime tt("SoftReference", trace_time, false, gclog_or_tty);
process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
is_alive, keep_alive, complete_gc, task_executor);
}
update_soft_ref_master_clock();
// Weak references
{
TraceTime tt("WeakReference", trace_time, false, gclog_or_tty);
process_discovered_reflist(_discoveredWeakRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}
函数process_discovered_reflist具有以下签名:
void
ReferenceProcessor::process_discovered_reflist(
DiscoveredList refs_lists[],
ReferencePolicy* policy,
bool clear_referent,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor)
这表明WeakRefs被ReferenceProcessor :: process_discovered_references无条件清除。
在process_discovered_reference中搜索热点代码显示CMS收集器(我正在使用的)从以下调用堆栈调用此方法。
CMSCollector::refProcessingWork
CMSCollector::checkpointRootsFinalWork
CMSCollector::checkpointRootsFinal
此调用堆栈看起来每次运行CMS集合时都会调用它。
假设这是真的,对长期存在的弱引用对象的唯一解释可能是一个微妙的JVM错误,或者如果GC没有运行。
答案 1 :(得分:1)
您可能想检查是否泄漏了类加载器问题。有关此主题的更多信息,请参阅this博客文章
答案 2 :(得分:0)
您需要澄清Foo
和WeakReference
之间的链接。案例
class Wrapper<T> extends WeakReference<T> {
private final T referent;
public Wrapper(T referent) {
super(t);
this.referent = referent;
}
}
与
非常不同class Wrapper<T> extends WeakReferece<T> {
public Wrapper(T referent) {
super(t);
}
}
或其内联版本WeakReference<Foo> wr = new WeakReference<Foo>(foo)
。
所以我认为你的情况与我在我的第一个代码片段中描述的情况不同。
正如您所说,您正在与JNI合作,您可能想要检查您是否有任何不安全的终结器。每个终结器应该finally
阻止调用super.finalize()
,并且很容易滑动。
您可能需要告诉我们更多有关对象性质的信息,以提供更好的创意。
答案 3 :(得分:0)
@iirekm No:WeakReferences比SoftReferences“弱”,这意味着在SoftReference之前,WeakReference总是被垃圾收集。
此帖中的更多信息:Understanding Java's Reference classes: SoftReference, WeakReference, and PhantomReference
编辑:(阅读评论后)肯定弱的参考文献比SoftReferences“弱”,错字。 :S
这里有一些用例可以进一步阐明这个主题:
这就是说,没有什么能阻止虚拟机(如果我错了请纠正我)让弱可达对象保持活动,只要它没有内存不足(如原作者的情况)。 / p>
这是我在该主题上可以找到的最佳资源:http://www.pawlan.com/monica/articles/refobjs/
编辑2:在PhantomRef中清除前面添加“待”
答案 4 :(得分:0)
我不熟悉Java,但你可能正在使用generational garbage collector,这将保持你的Foo和FooWeakRef对象单独(不收集),只要
指示垃圾收集发生的日志是否区分主要和次要集合?
答案 5 :(得分:0)
对于声称在软引用之前清除弱引用的非信徒:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
ReferenceQueue<Object> q = new ReferenceQueue<Object>();
Map<Reference<?>, String> referenceToId = new HashMap<Reference<?>, String>();
for(int i=0; i<100; ++i) {
Object obj = new byte [10*1024*1024]; // 10M
SoftReference<Object> sr = new SoftReference<Object>(obj, q);
referenceToId.put(sr, "soft:"+i);
WeakReference<Object> wr = new WeakReference<Object>(obj, q);
referenceToId.put(wr, "weak:"+i);
for(;;){
Reference<?> ref = q.poll();
if(ref == null) {
break;
}
System.out.println("cleared reference " + referenceToId.get(ref) + ", value=" + ref.get());
}
}
}
}
如果用-client或-server运行它,你会看到软引用总是在弱引用之前被清除,这也与Javadoc一致:http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ref/package-summary.html#reachability
通常,软/弱引用与Maps一起使用以生成各种缓存。如果你的Map中的键与==运算符(或来自Object的unoverriden .equals)进行比较,那么最好使用在SoftReference键上运行的Map(例如来自Apache Commons) - 当对象'消失'时,其他任何对象都不会在'=='意义上与旧的相等。如果将Map的键与高级.equals()运算符(如String或Date)进行比较,则许多其他对象可能与“消失”对象匹配,因此最好使用标准的WeakHashMap。
答案 6 :(得分:-1)
尝试使用SoftReference。 Javadoc说:在虚拟机抛出OutOfMemoryError之前,所有对软可访问对象的软引用都保证已被清除。
WeakReference没有这样的保证,这使它们更适合缓存,但有时SoftReferences更好。