【发布时间】:2017-05-29 12:07:00
【问题描述】:
对于我的服务器应用程序,我使用 WeakReferences 列表来保持计数并处理与服务器的活动会话。我正在运行定期 gc 以清理非活动会话列表,但由于某种原因,始终保留一个参考。根据覆盖的 finalize 方法,这是创建的最后一个会话。
我不知道为什么会这样。我首先认为这可能是由于静态方法或变量,但现在我已经从 ClientHandlerThread 类中删除了这些对象。服务器类没有其他引用,但弱引用列表。目前这对我来说不是一个大问题,但是更好地了解 java 如何选择要进行垃圾收集的对象可以在将来使用。 :) 下面是最重要的代码 sn-ps:
Server.java:
public class Server {
private List<WeakReference<ClientHandlerThread>> m_connectedClients =
Collections.synchronizedList(
new ArrayList<WeakReference<ClientHandlerThread>>());
/** Counter to identify sessions */
private static AtomicInteger m_NumSession = new AtomicInteger(0);
Server() {
SSLServerSocket sslDataTraffic = null;
// Sockets are initialized here - code removed for clarity
// Run periodic GC
Thread stThread = new Thread() {
public void run() {
do {
try {
Thread.sleep(5000);
}
catch (InterruptedException ignore) {}
System.runFinalization();
System.gc();
cleanUpSessionsList();
} while (true);
}
};
stThread.setPriority(Thread.MIN_PRIORITY);
stThread.start();
// Listen to new connections, create handlers and add to list
while (true) {
try {
SSLSocket sslDataTrafficSocketInstance =
(SSLSocket) sslDataTraffic.accept();
ClientHandlerThread c = new ClientHandlerThread(
sslDataTrafficSocketInstance,
m_NumSession.incrementAndGet());
c.start();
m_connectedClients.add(new WeakReference<>(c));
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** Clean any old references and return the number of active connections
* @return
*/
public int cleanUpSessionList() {
int i = 0;
synchronized(m_connectedClients) {
Iterator<WeakReference<ClientHandlerThread>> it =
m_connectedClients.iterator();
while (it.hasNext()) {
WeakReference<ClientHandlerThread> sessionRef = it.next();
if (sessionRef.get() == null)
it.remove();
else
i++;
}
}
System.out.println("Active sessions: " + i");
return i;
}
}
ClientHandlerThread.java:
public class ClientHandlerThread extends Thread {
private int m_SessionID;
private SSLSocket dataSocket;
public ClientHandlerThread(
SSLSocket dataSocket,
int sessionID) {
this.dataSocket = dataSocket;
m_SessionID = sessionID;
}
public void run() {
// code removed
}
@Override
protected void finalize() throws Throwable {
System.out.println("Session " + m_SessionID + " finalized");
super.finalize();
}
}
【问题讨论】:
-
不保证会收集未引用的对象,尤其是当它们覆盖
finalize时。这种覆盖会产生可怕的后果。这里使用finalize是不恰当的,不应该这样做。 -
你能澄清你所说的覆盖 finalize 会产生可怕的后果是什么意思吗?在这种情况下,如果调用该方法,我只会打印调试字符串,并且我完全知道根据 java doc 可能永远不会调用它。然而,这个方法“从不”调用的唯一对象似乎是 WeakReference 列表中最新添加的对象 - 直到添加另一个对象。
-
你是认真地要求我们做你的研究吗?好吧,好吧,但只要你知道几分钟的在线搜索就会产生奇迹。无论如何,具有“非平凡”
finalize的对象至少需要两个 GC 周期来收集,这会增加内存压力。它可能会挂在原本会被收集的引用上,从而增加内存压力。无法保证对finalize的调用顺序,并且可以跳过对象,将另一轮GC 添加到它们的集合中,并增加内存压力。还有更多。请自行查找。 -
我同意添加此方法有其缺点,但在这种情况下,无论是否包含该方法,结果都是相同的。困扰我的是所有其他对象如何及时收集,但最新的始终保留。不过,谢谢你的回答。 :)
-
执行堆快照,通过 eclipse MAT 等内存分析器运行它。看看这些物体上的东西。
标签: java garbage-collection weak-references