调用System.gc()导致JSP中的数据丢失

时间:2010-08-04 07:32:09

标签: java jsp garbage-collection

我目前正在调试一个导致间歇性问题的Web应用程序,尤其是当命中率很高时。当给每个新用户一个包含个性化导航菜单的会话时,我想我会试着看看会话变量需要多少内存。

在处理会话对象创建的JSP的代码部分中,我添加了以下代码:

System.gc();
long orgHeap = Runtime.getRuntime().freeMemory();

... create session variables ...

System.gc();
log.info("Heap delta: " + (Runtime.getRuntime().freeMemory() - orgHeap));

让我感到惊讶的是,添加System.gc()会破坏应用程序。它不再起作用,因为有些物体会丢失(或者看起来如此)。已初始化的值为null。当删除gc()调用时,应用程序正常工作。 gc()应该只删除已被标记为删除的对象 - 对吗?

还有其他人有类似的问题吗?

2 个答案:

答案 0 :(得分:2)

我能想到的唯一一个案例就是如果您正在使用WeakReference s(或过期的SoftReference s,在这种情况下大致相似)引用您仍想保留的对象。可能进入GC收集的状态的对象;但在它实际运行之前,你仍然可以通过你的参考资料与他们联系。调用System.gc(),即使它没有任何保证语义,也可能导致收集器运行并收集所有这些弱可达对象。

但这似乎不太可能,因为

  1. 无意中将WeakReferences用于强可达对象似乎不是一个容易犯的错误。即使你正在使用库,我也很难想到你可能会错误地使用弱引用的情况。
  2. 如果确实发生了这种情况,那么应用程序的行为无论如何都是不确定的。垃圾收集可能随时发生,因此如果没有System.gc()调用,您可能会看到不一致的行为。你总是会有一些代码在收集之后运行,因此无法找到它的指示对象。
  3. System.gc()理论上不会做任何事情,因此不应该造成这种情况。
  4. 最后一点是重要的一点 - 你为什么要调用System.gc(),这几乎总是适得其反?我不相信你有合法的需要来打电话,它不会做你可以依赖的任何事情,显然它会打破你的申请。

    因此,如果您的应用在没有拨打电话的情况下正常工作,那就停止制作吧。

    我仍然会考虑检查你的应用程序如何组合在一起,因为这不是问题的实际原因,你可能有一个更深层次的问题,这个问题非常脆弱,只是等待你以后再打破。

    编辑:另一个可能的原因可能是简单的时间安排。拨打System.gc()可能需要花费不可忽视的时间。在此期间,其他线程可以以GCing线程不期望的方式进行并更改状态。因此,当它从呼叫返回时,世界状态打破了它的期望,因此导致逻辑错误。同样,这只是猜测,但比WeakReference更合理。

答案 1 :(得分:0)

垃圾收集永远不会删除活动对象,因此我认为您的问题出在其他地方。

正如你所说,这是负载 - “命中率很高” - 这可能是一个使用EJB错误的情况,你期望发生一些事情,因为它在低负载下这样做(比如在询问时反复获取相同的EJB)对于它)但是在高负荷下的变化(其他人得到了那个EJB,你得到另一个)。