有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java映射清除vs null

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

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


共 (6) 个答案

  1. # 1 楼答案

    我觉得取消现有映射比clear()更便宜。因为在现代JVM中,对象的创建非常便宜

  2. # 2 楼答案

    简短回答:使用Collection.clear(),除非太复杂而无法将collection放在周围

    详细答案:在Java中,内存分配几乎是瞬时的。它不仅仅是在虚拟机内部移动的指针。然而,这些对象的初始化可能意味着一些重要的事情。此外,所有使用内部缓冲区的对象都可以调整其内容的大小并进行复制。使用clear()确保缓冲区最终稳定到某个维度,这样就不需要重新分配内存,也不需要将旧缓冲区复制到新缓冲区

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

  3. # 3 楼答案

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

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

  4. # 4 楼答案

    您可以使用这两种方法获得相似的结果

    先前的一个回答指出clear在成熟的map实现中需要固定的时间。如果不检查像HashMapTreeMapConcurrentHashMap这样的源代码,我希望他们的clear方法需要固定的时间,加上amortized垃圾收集成本

    另一张海报指出,共享地图不能为空。如果你想的话可以,但是你可以使用一个proxy对象来封装一个适当的映射,并在需要时将其置空。当然,您必须自己实现代理映射类

    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和null out在重要的方面是等价的,但我认为更成熟的假设是,你的地图,即使目前没有共享,也可能在以后由于你无法预见的力量而被共享

    还有另一个原因是clear而不是置零,即使映射没有共享。您的映射可能由外部客户端(如factory)实例化,因此,如果通过将映射置零来清除映射,您可能会不必要地将自己coupling送到工厂。为什么清除地图的对象必须知道您使用Guava的Maps.newHashMap()实例化了地图,并且使用了上帝知道的参数?即使这在您的项目中不是一个现实的问题,但将您自己与成熟实践结合起来仍然是值得的

    基于上述原因,在其他条件相同的情况下,我将投票支持clear

  5. # 5 楼答案

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

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

    这允许您重用变量,而不必将其设置为null,您将自动放弃对旧映射的引用。在非内存管理的应用程序中,这是一种糟糕的做法,因为它们必须引用旧指针来清除它(在其他语言中,这是一个悬空指针),但在Java中,由于没有任何引用,GC将其标记为符合收集条件

  6. # 6 楼答案

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