地图清除与空



我有一个地图,我用它来存储动态数据,这些数据在创建(即使用;它们被快速消耗)后立即被丢弃。它响应用户交互,因为当用户单击按钮时,地图将被填充,然后数据用于执行某些工作,然后不再需要地图。

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

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

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

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

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

这允许您重用变量而不将其设置为 null,您可以静默地丢弃对旧映射的引用。 这在非内存托管应用程序中是残酷的做法,因为它们必须引用旧指针才能清除它(这是其他语言中的悬空指针),但在 Java 中,由于没有引用此内容,GC 将其标记为有资格收集。

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

简短的回答:使用Collection.clear(),除非它太复杂而无法保持collection

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

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

如果您始终持有地图,则会提示给老一代。如果每个用户都有一个对应的地图,则旧一代的地图数量与用户的数量成正比。当用户数量增加时,它可能会更频繁地触发完整 GC。

您可以同时使用两者,结果相似。

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

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

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而不是清空,即使地图未共享。您的地图可能由外部客户端(如工厂)实例化,因此,如果您通过清空地图来清除地图,则最终可能会不必要地将自己耦合到工厂。为什么清除地图的对象必须知道您使用番石榴的Maps.newHashMap()实例化地图,而上帝知道哪些参数?即使这在您的项目中不是一个现实的问题,使自己与成熟的实践保持一致仍然是值得的。

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

呵。

最新更新