[英]Is an abstract superclass garbage collected when the last instance of the subclass is collected?
I have an abstract class which I use to expire instances of a subclass: 我有一个抽象类,用于终止子类的实例:
public abstract class Expirable {
private transient Timer timer;
protected abstract void onExpire();
protected void setExpire(long delay) {
resetExpire();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
resetExpire();
onExpire();
}
}, delay
);
}
protected void resetExpire() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
}
I extend any class and overide onExpire
, then I call setExpire(delay)
from the subclass (not shown): 我扩展任何类并覆盖onExpire
,然后从子类(未显示)调用setExpire(delay)
):
public class MyClass extends Expirable {
@Override
protected void onExpire() {
// expiration code here
}
}
This class works perfectly fine, but the timer
object is very expensive. 此类工作得很好,但是timer
对象非常昂贵。 Because I have tens of thousands of instances, I wrote a cheap version with the same functionality, which uses a single timer
scheduled at a fixed rate and a queue
. 因为我有成千上万的实例,所以我写了一个便宜的版本,它具有相同的功能,它使用以固定速率安排的单个timer
和一个queue
。 Not as precise, but cheap. 没有那么精确,但是便宜。
public abstract class ExpirableCheap {
private static final long COLLECTOR_INTERVAL_MSEC = 1000;
private static final int INITIAL_CAPACITY = 128;
private static Queue<ExpirableCheap> queue = new PriorityBlockingQueue<>(
INITIAL_CAPACITY,
Comparator.comparingLong(expirable -> expirable.expiresWhen)
);
@SuppressWarnings("FieldCanBeLocal")
private static TimerTask timerTask;
@SuppressWarnings("FieldCanBeLocal")
private static Timer timer;
static {
timerTask = new TimerTask() {
@Override
public void run() {
// this Runnable stops working
long time = new Date().getTime();
while (queue.peek() != null && queue.peek().expiresWhen < time) {
queue.poll().onExpire();
}
}
};
timer = new Timer();
timer.scheduleAtFixedRate(timerTask,
COLLECTOR_INTERVAL_MSEC,
COLLECTOR_INTERVAL_MSEC
);
}
private transient long expiresWhen;
protected abstract void onExpire();
protected synchronized void setExpire(long delay) {
resetExpire();
long time = new Date().getTime();
expiresWhen = time + delay;
queue.offer(this);
}
protected synchronized void resetExpire() {
queue.remove(this);
}
}
Obviously, the static code block is executed once and schedules the timer
in regular intervals. 显然,静态代码块执行一次,并以固定的时间间隔计划timer
。 The timerTask
peeks at the queue and calls onExpire()
. timerTask
窥视队列并调用onExpire()
。
What's wrong? 怎么了?
This runs fine for a while, but then suddenly the timerTask
is no longer executed. 可以运行一会儿,但是突然之间, timerTask
不再执行。 When testing, it works fine and I cannot simulate the situation, but it fails after some time in production. 测试时,它可以正常工作,我无法模拟这种情况,但是在生产一段时间后失败。
I am not sure what happens, but I suspect the static variables which I initialized in the static code block are garbage collected when the last instance of the subclass is collected. 我不确定会发生什么,但是我怀疑在收集子类的最后一个实例时,我在静态代码块中初始化的静态变量被垃圾回收了。 Then, when the class is re-used, the static code block is not run again. 然后,当重新使用该类时,将不再运行静态代码块。 In other words, it seems to work until there are no instances anymore which extend ExpirableCheap
. 换句话说,它似乎可以工作,直到不再有extend ExpirableCheap
实例extend ExpirableCheap
。
Strangely, the queue
persists, reason why I expected an exception to happen inside the Runnable
, which I believe is not the case. 奇怪的是, queue
仍然存在,这就是为什么我希望Runnable
内发生异常的原因,我认为事实并非如此。
As you can see, I tried to move timer
and timerTask
variables from the static code block into member variables (which didn't help). 如您所见,我试图将timer
和timerTask
变量从静态代码块移到成员变量中(这没有帮助)。 I also tried to synchronize setExpire()
and resetExpire()
, which I believe makes no difference either. 我还尝试同步setExpire()
和resetExpire()
,我认为这也没有什么区别。
Can anybody see what's happening? 有人可以看到发生了什么吗? Did I make another stupid mistake and am I on the wrong track? 我是否犯了另一个愚蠢的错误,是否走错了轨道?
Any suggestions what I could change to make this work? 有什么建议我可以更改以使其正常工作吗?
As @TimBiegeleisen correctly pointed out, Java works as expected. 正如@TimBiegeleisen正确指出的那样,Java可以按预期工作。 An abstract superclass is NOT garbage collected when the last instance of the subclass is collected. 在收集子类的最后一个实例时,不会垃圾收集抽象超类。
My problem was unrelated. 我的问题无关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.