想象一下这个示例java类:
class A {
void addListener(Listener obj);
void removeListener(Listener obj);
}
class B {
private A a;
B() {
a = new A();
a.addListener(new Listener() {
void listen() {}
}
}
Run Code Online (Sandbox Code Playgroud)
我是否需要向B添加finalize方法以调用a.removeListener?假设A实例也将与其他一些对象共享,并且将比B实例更长.
我担心我可能会在这里创建垃圾收集器问题.什么是最佳做法?
jan*_*anm 17
参考图中有一个循环.引用B和B引用A.垃圾收集器将检测周期并查看何时没有对A和B的外部引用,然后将收集两者.
试图在这里使用终结器是错误的.如果B被销毁,则对A的引用也将被删除.
声明:"假设A实例也将与其他一些对象共享,并且将比B实例更长." 是错的.唯一的方法是如果从终结器以外的某个地方明确地删除了监听器.如果传递对A的引用,那将意味着对B的引用,并且B将不会被垃圾收集,因为存在对AB循环的外部引用.
进一步更新:
如果要打破循环并且不要求B显式删除侦听器,则可以使用WeakReference.像这样的东西:
class A {
void addListener(Listener obj);
void removeListener(Listener obj);
}
class B {
private static class InnerListener implements Listener {
private WeakReference m_owner;
private WeakReference m_source;
InnerListener(B owner, A source) {
m_owner = new WeakReference(owner);
m_source = new WeakReference(source);
}
void listen() {
// Handling reentrancy on this function left as an excercise.
B b = (B)m_owner.get();
if (b == null) {
if (m_source != null) {
A a = (A) m_source.get();
if (a != null) {
a.removeListener(this);
m_source = null;
}
}
return;
}
...
}
}
private A a;
B() {
a = new A();
a.addListener(new InnerListener(this, a));
}
}
Run Code Online (Sandbox Code Playgroud)
如果需要跨多个类可以进一步推广.
我刚刚发现了一个巨大的内存泄漏,所以我将调用创建泄漏的代码是错误的,而我的修复不会泄漏是正确的。
这是旧代码:(这是我见过的常见模式)
class Singleton {
static Singleton getInstance() {...}
void addListener(Listener listener) {...}
void removeListener(Listener listener) {...}
}
class Leaky {
Leaky() {
// If the singleton changes the widget we need to know so register a listener
Singleton singleton = Singleton.getInstance();
singleton.addListener(new Listener() {
void handleEvent() {
doSomething();
}
});
}
void doSomething() {...}
}
// Elsewhere
while (1) {
Leaky leaky = new Leaky();
// ... do stuff
// leaky falls out of scope
}
Run Code Online (Sandbox Code Playgroud)
显然,这很糟糕。许多 Leaky 正在被创建,但永远不会被垃圾收集,因为侦听器使它们保持活力。
这是我修复内存泄漏的替代方案。这是有效的,因为我只关心对象存在时的事件侦听器。侦听器不应让对象保持活动状态。
class Singleton {
static Singleton getInstance() {...}
void addListener(Listener listener) {...}
void removeListener(Listener listener) {...}
}
class NotLeaky {
private NotLeakyListener listener;
NotLeaky() {
// If the singleton changes the widget we need to know so register a listener
Singleton singleton = Singleton.getInstance();
listener = new NotLeakyListener(this, singleton);
singleton.addListener(listener);
}
void doSomething() {...}
protected void finalize() {
try {
if (listener != null)
listener.dispose();
} finally {
super.finalize();
}
}
private static class NotLeakyListener implements Listener {
private WeakReference<NotLeaky> ownerRef;
private Singleton eventer;
NotLeakyListener(NotLeaky owner, Singleton e) {
ownerRef = new WeakReference<NotLeaky>(owner);
eventer = e;
}
void dispose() {
if (eventer != null) {
eventer.removeListener(this);
eventer = null;
}
}
void handleEvent() {
NotLeaky owner = ownerRef.get();
if (owner == null) {
dispose();
} else {
owner.doSomething();
}
}
}
}
// Elsewhere
while (1) {
NotLeaky notleaky = new NotLeaky();
// ... do stuff
// notleaky falls out of scope
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13865 次 |
| 最近记录: |