13

我有一张用于存储动态数据的地图,这些数据一经创建就被丢弃(即使用;它们很快被消耗)。它响应用户交互,即当用户单击按钮时,地图被填充,然后数据用于完成一些工作,然后不再需要地图。

所以我的问题是清空地图的更好方法是什么?我应该每次都将它设置为 null 还是应该打电话clear()?我知道 clear 在时间上是线性的。但我不知道如何将该成本与每次创建地图的成本进行比较。地图的大小不是恒定的,认为它可能会在创建之间运行 n 到 3n 个元素。

4

6 回答 6

8

如果一个地图没有被其他对象引用,而其他对象可能很难设置一个新地图,那么简单地null删除一张旧地图并从头开始可能比调用 a 更轻clear(),因为不需要进行线性时间清理。由于现代系统上的垃圾收集成本很小,因此您很有可能通过这种方式节省一些 CPU 周期。您可以通过指定初始容量来避免多次调整地图大小。

首选的一种情况clear()是地图对象在系统中的多个对象之间共享时。例如,如果您创建一个地图,将其提供给多个对象,然后在其中保留一些共享信息,则将地图设置为所有这些对象中的新地图可能需要保留对具有该地图的对象的引用。在这种情况下,继续调用clear()同一个共享地图对象会更容易。

于 2013-10-24T01:19:59.067 回答
2

好吧,这取决于您可以投入多少内存。如果你有很多,那没关系。但是,将映射本身设置为 null 意味着您已经释放了垃圾收集器 - 如果只有映射具有对其中实例的引用,那么垃圾收集器不仅可以收集映射,还可以收集其中的任何实例。Clear 确实清空了映射,但它必须遍历映射中的所有内容以将每个引用设置为 null,这发生在您可以控制的执行时间 - 垃圾收集器基本上必须做这项工作,所以让它去做它的东西。请注意,将其设置为 null 不会让您重用它。重用映射变量的典型模式可能是:

Map<String, String> whatever = new HashMap<String, String();
// .. do something with map
whatever = new HashMap<String, String>();

这使您可以重用变量而不将其设置为 null,您会默默地丢弃对旧地图的引用。这在非内存管理的应用程序中是一种恶劣的做法,因为它们必须引用旧指针来清除它(在其他语言中这是一个悬空指针),但在 Java 中,因为没有引用这个,GC 将其标记为符合收集条件。

于 2013-10-24T01:19:51.870 回答
0

我觉得将现有地图归零比clear(). 因为在现代 JVM 中创建对象非常便宜。

于 2013-10-24T01:21:49.527 回答
0

简短的回答Collection.clear()除非太复杂而无法保持collection环绕,否则请使用。

详细解答:在Java中,内存的分配几乎是瞬时的。它只不过是一个在 VM 内移动的指针。但是,这些对象的初始化可能会增加一些重要的东西。此外,所有使用内部缓冲区的对象都可以调整大小和复制其内容。使用clear()确保缓冲区最终稳定到某个维度,这样就永远不需要重新分配内存和将旧缓冲区复制到新缓冲区。

另一个重要问题是重新分配然后释放大量对象将需要更频繁地执行垃圾收集器,这可能会导致突然延迟。

于 2013-10-24T01:25:24.833 回答
0

如果你一直拿着地图,它会被提示到老一代。如果每个用户都有一张对应的地图,那么老年代的地图数量与用户数量成正比。当用户数增加时,可能会更频繁地触发 Full GC。

于 2013-10-24T01:41:01.653 回答
0

您可以使用两者来获得相似的结果。

一个先前的答案指出,clear在成熟的地图实施中预计需要恒定的时间。如果不检查 , ,之类的源代码HashMap,我希望他们的方法需要恒定的时间,加上摊销的垃圾收集成本。TreeMapConcurrentHashMapclear

另一位发帖人指出,共享地图不能为空。好吧,如果你想要它可以,但是你可以通过使用一个代理对象来做到这一点,该对象封装了一个适当的映射并在需要时将其清空。当然,您必须自己实现代理地图类。

Map<Foo, Bar> myMap = new ProxyMap<Foo, Bar>();
    // Internally, the above object holds a reference to a proper map,
    // for example, a hash map. Furthermore, this delegates all calls
    // to the underlying map. A true proxy.
myMap.clear();
    // The clear method simply reinitializes the underlying map.

除非你做了类似上面的事情,clear并且在重要的方面无效化是等价的,但我认为假设你的地图,即使当前没有共享,可能会在以后因为你不能共享的力量而变得更成熟预见。

clear即使地图未共享,也有另一个原因而不是无效。您的地图可能由外部客户端(如factory )实例化,因此如果您通过将地图清空来清除地图,您最终可能会不必要地将自己与工厂耦合。为什么清除地图的对象必须知道您使用 Guava 实例化您的地图Maps.newHashMap(),上帝知道哪些参数?即使这在您的项目中不是一个现实的问题,但让自己与成熟的实践保持一致仍然是值得的。

由于上述原因,在其他条件相同的情况下,我会投票给clear.

HTH。

于 2013-10-24T01:56:02.177 回答