在移动设备中调用System.gc()

时间:2009-05-22 18:19:11

标签: java java-me garbage-collection

我必须维护一个J2ME应用程序。应用程序中有很多System.gc()。在调用System.gc()之前,所有属性都设置为null。将属性设置为null是否有意义?调用System.gc()是否有意义?在必要时,jvm不应该调用垃圾收集器吗?

5 个答案:

答案 0 :(得分:2)

在一台优秀的现代VM上,调用System.gc()通常没什么意义。将属性设置为null通常没有意义,除非这是使它们无法访问的唯一方法。

可能在移动设备上获得的不太复杂的VM上,如果引用不再在某个方法的某个部分使用但仍在范围内,则将引用置零是有意义的。 (在像Hotspot这样的现代桌面虚拟机上,通常不再需要这种虚拟机 - 虚拟机将代码置于其前面,无论范围如何,通常都可以确定您是否仍将使用本地引用。)< / p>

现在,回到System.gc(),移动虚拟机在历史上比我们习惯使用的相当复杂的“完全成熟”的虚拟机更简单,例如Hotspot。但是:

  • 移动虚拟机近年来发生了很多事情 - 对象吞吐量与性能的其他方面一样,在许多设备上都有明显的改进;
  • 无论如何, System.gc()没有一致的,明确定义的行为。在某些设备上,它可能什么都不做;在其他方面,与桌面虚拟机一样,与应用程序运行时VM自动执行的正常“渐进式”垃圾收集相比,它可能会导致一种实际损害性能的垃圾收集。

所以我会非常谨慎使用System.gc()。

答案 1 :(得分:2)

这是Java世界的一个重要城市传奇,呼叫System.gc()实际上可以为您做一些可靠的事情。它不会。

仅仅建议JVM尝试做某事。 Javadoc for the method在这方面有目的地含糊不清。

另一个大问题是引用归零。当引用超出范围时,它已经被VM清空,这样做本身就是多余的和误导性的。如果还有其他引用,它们仍然可用,你的任务将什么也不做(除非你去访问所有其他可用的参考 - 但那么,重点是什么?这就是VM已经在做什么)。

所以回答你的问题:

  • 将属性设置为null很少有意义。正确设计您的软件,以便在您不再使用它们时引用超出范围。
  • 调用System.gc()很少有意义。让JVM为您完成工作 - 这就是我们使用VM而不是管理自己内存的原因。
  • 是的,让VM管理您的内存,它会在需要时运行GC。但是,如果您的软件设计很差,它可能会破坏VM中的GC。在这种情况下,追踪你的内存泄漏并重构软件(说起来容易做起来难。)

答案 2 :(得分:2)

到目前为止,这个问题的所有答案都是完全正确的,主要是你不能依赖System.gc()来做任何事情。它是特定于平台的,MIDP2没有给出任何关于它应该如何表现的真实规范。

然而,它通常以合适的方式实现,虽然您不能说“此对象现在已删除”等,但我相信在某些情况下使用该呼叫是可以接受和建议的。例如,如果您的应用程序需要执行大量删除然后分配(例如重置或更改状态),立即进行调用将告诉VM - 现在是收集的好时机。

詹姆斯

答案 3 :(得分:1)

所有归零属性和System.gc()调用的原因绝对是打击设备碎片的一部分。很容易说你自己永远不应该忽略一个值,你应该让它超出范围,实际上这是PC开发的合适方式。然而,移动空间是一个完全不同的动物,如果说你可以在有限的移动设备上以同样的方式处理内存管理,就像你在拥有演出和演出RAM的PC上一样。

即使是现在,高端智能手机也有大约32-64MB的堆可用于J2ME应用程序。许多设备仍然大约1-4MB,并且通常为了满足运营商规范,您需要针对更小的堆大小。 Razr只有800K的堆,并且仍然需要大多数运营商支持,因为他们的许多用户仍然使用该设备。

发生内存碎片是因为即使一块内存不再使用,它​​已经无效,但在垃圾收集之前它还没有可用。大多数移动虚拟机仅在需要内存时才使用GC。因此,当它最终运行GC时,堆可能会碎片化为很小的内存块。当需要分配更大的内存块时,它将无法分配给较小的块。如果你有足够的这些较小的块污染堆,没有提供足够大的块来容纳更大的对象,最终你会得到一个OutOfMemory异常,即使看起来你有大量的可用内存。

例如,假设您创建了一个需要50个字节的本地Object变量。接下来,您将分配一个成员变量,该变量将在应用程序的整个生命周期中保留,该变量需要存在200个字节的堆。如果你一遍又一遍地执行这个过程,你可能会遇到数千个内存块长度只有50个字节的情况。因为持久对象需要200个字节,所以最终会被搞砸并获得OutOfMemory异常。

现在如果你创建了相同的String对象,使用它,然后自己去掉它并调用System.gc()(你也可以调用Thread.yield()来给GC一个运行的机会)然后你会有50个字节可用于创建新的持久对象,避免碎片并避免最终的OutOfMemory异常。

这是一个非常基本的例子,但是如果您在游戏应用程序中有很多大图像,那么您在移动领域会很快遇到这种情况。

最后一点,使用BlackBerry设备时,您应该避免自己调用垃圾收集器,因为它更加复杂(它会为您整理碎片堆)。更复杂使得它比大多数设备上的正常向下和脏的GC慢得多(我们说每次运行几秒钟)。

答案 4 :(得分:0)

将属性设置为null(从而破坏对对象的一些引用)GC将声明这些对象。也许他们不再需要了,开发者想要释放一些记忆?

我听说并非每个J2ME目标都有 GC。但是如果确实如此,那么调用System.gc()是有意义的,这样当你做一些实时工作时垃圾收集器就不会启动。