5

我开发了一个 J2ME Web 浏览器应用程序,它运行良好。我正在测试它的内存消耗。在我看来,它存在内存泄漏,因为代表内存监视器(无线工具包)消耗的内存的绿色曲线达到了浏览器每完成 7 个请求所分配的最大内存(即 687768 字节),(即当最终用户在 Web 浏览器中从一页导航到另一页 7 页)之后,垃圾收集器运行并释放分配的内存。

我的问题是:

  • 当垃圾收集器每 7 页导航自动运行时,它是内存泄漏吗?
  • 我是否需要为每个请求手动运行一次垃圾收集器 (System.gc()) 以防止达到最大分配内存?

请指导我,谢谢

4

5 回答 5

3

要确定它是否是内存泄漏,您需要更多地观察它。

根据您的描述,即一旦达到最大内存,GC 就会启动并能够释放内存以供您的应用程序运行,这听起来不像有泄漏。

你也不应该自己打电话给GC,因为

  1. 这只是一个迹象
  2. 可能会影响底层算法,从而影响其性能。

相反,您应该关注为什么您的应用程序在如此短的时间内需要如此多的内存。

于 2012-09-16T11:19:06.313 回答
1

我的问题是:当垃圾收集器每 7 页导航自动运行一次时,是否存在内存泄漏?

不必要。也可能是:

  • 您的堆对于您要解决的问题的大小来说太小了,或者

  • 您的应用程序正在高速生成(可收集的)垃圾。

事实上,鉴于您提供的数字,我倾向于认为这主要是一个堆大小问题。如果 GC 运行之间的间隔随着时间的推移而减少,那么这将是指向内存泄漏的证据,但如果速率保持平均稳定,则表明内存使用率和回收率处于平衡状态;即没有泄漏。

我是否需要为每个请求手动运行一次垃圾收集器 (System.gc()) 以防止达到最大分配内存?

不不不。

调用System.gc()不会治愈内存泄漏。如果是真正的内存泄漏,那么调用System.gc()不会回收泄漏的内存。事实上,你要做的就是让你的应用程序运行得慢很多……假设 JVM 没有完全忽略调用。


HotSpot JVM 的默认行为是尊重 System.gc() 调用的直接和间接证据:

并且来自 Java 7 源代码:

./openjdk/hotspot/src/share/vm/runtime/globals.hpp

  product(bool, DisableExplicitGC, false,                                   \
          "Tells whether calling System.gc() does a full GC")               \

其中false是选项的默认值。(请注意,这是在代码树的 OS / M/C 独立部分。)

于 2012-09-16T12:00:43.517 回答
1

我写了一个库,努力强制 GC。如前所述,System.gc()它是异步的,它自己不会做任何事情。您可能希望使用此库来分析您的应用程序并找到产生过多垃圾的位置。你可以在这篇文章中阅读更多关于它的内容,我详细描述了 GC 问题。

于 2012-11-23T02:45:41.080 回答
0

那是(半)正常行为。在堆大小达到某个阈值之前,不会收集可用(未引用)存储,从而触发收集周期。

您可以通过更加“堆感知”来减少 GC 周期的频率。例如,许多程序中的一个常见错误是通过使用子字符串来解析字符串,不仅解析出最左边的单词,而且还通过向右子字符串化来缩短剩余的字符串。为单词创建一个新字符串不容易避免,但可以很容易地避免重复对原始字符串的“尾部”进行子串化。

运行 System.GC 将一事无成——在大多数平台上它是无操作的,因为它经常被滥用。

请注意(在脑死亡的 Android 之外)您不能在 Java 中出现真正的“内存泄漏”(除非存在严重的 JVM 错误)。Java 中通常所说的“泄漏”是未能删除对不再使用的对象的所有引用。例如,您可能会一直将数据放入链中,并且永远不会清除指向链远端不再使用的内容的指针。所产生的症状是使用的 MINIMUM 堆(即 GC 运行后立即的大小)在每个循环中不断上升。

于 2012-09-16T12:26:06.357 回答
0

添加到其他出色的答案:

看起来您将内存泄漏垃圾收集混淆了。

内存泄漏是当未使用的内存无法被垃圾收集时,因为它仍然在某处有引用(尽管它们没有用于任何事情)。

垃圾收集是指某个软件(垃圾收集器)自动释放未引用的内存。

您不应手动调用垃圾收集器,因为这会影响其性能。

于 2012-09-16T15:22:26.243 回答