我的问题是:
- 当垃圾回收器每7次页面导航自动运行时,这是否意味着存在内存泄漏?
- 我是否需要手动运行垃圾回收器(System.gc())一次来防止达到最大分配内存?
调用System.gc()
不能解决内存泄漏问题。如果确实存在内存泄漏,那么调用System.gc()
也无法回收泄漏的内存。事实上,你所做的只是让应用程序运行得更慢...除非JVM完全忽略了这个调用。
有直接和间接的证据表明,HotSpot JVM 的默认行为是遵守 System.gc() 调用:
"例如,禁用DisableExplicitGC选项的默认设置会导致JVM遵守显式垃圾收集请求。" - http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.express.doc/info/exp/ae/rprf_hotspot_parms.html
"当以这种方式启用JMX时,一些JVM(如Sun的)进行分布式垃圾收集将定期调用System.gc,从而导致Full GC。" - http://static.springsource.com/projects/tc-server/2.0/getting-started/html/ch11s07.html
"最好使用标志-XX:+ DisableExplicitGC来禁用显式GC。" - http://docs.oracle.com/cd/E19396-01/819-0084/pt_tuningjava.html
来自Java 7源代码:
./openjdk/hotspot/src/share/vm/runtime/globals.hpp
product(bool, DisableExplicitGC, false, \
"Tells whether calling System.gc() does a full GC") \
其中 false
是该选项的默认值。(请注意,这是代码树中与操作系统/主机无关的部分。)
System.gc()
是异步的,本身不会做任何事情。您可以使用这个库来分析您的应用程序,并找出产生过多垃圾的地方。您可以在this article中阅读更多相关信息,其中我详细描述了垃圾回收问题。这是(半)正常的行为。只有当堆大小达到某个阈值时,触发收集周期,才会收集可用(未引用)存储。
您可以通过更加“堆感知”来减少GC周期的频率。例如,许多程序中的常见错误是使用substring解析字符串,不仅解析最左边的单词,而且还通过对右侧进行子字符串操作来缩短剩余的字符串。创建一个新的String以存储单词是无法避免的,但可以轻松避免重复对原始字符串的“尾部”进行子字符串操作。
运行System.GC将一无所获——在大多数平台上,它是一个空操作,因为它经常被滥用。
请注意,在Java之外(除了愚蠢的Android),您不能真正地出现“内存泄漏”(除非存在严重的JVM错误)。在Java中通常所说的“泄漏”是指未能删除所有对永远不会再次使用的对象的引用。例如,您可能会不断将数据放入链中,并且从不清除对链末端的东西的指针,而这些东西将不再使用。结果的症状是每个周期后使用的最小堆(即GC运行后的大小)不断上升。
除了其他出色的答案之外,还要补充一点:
看起来你把内存泄漏和垃圾回收混淆了。
内存泄漏是指未使用的内存无法进行垃圾回收,因为它仍然在某个地方有引用(尽管它们没有被用于任何事情)。
垃圾回收是指软件(垃圾收集器)自动释放未引用的内存。
您不应手动调用垃圾收集器,因为这会影响其性能。