Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 需要一个在添加和删除时不会产生任何垃圾的高效映射或集_Java_Data Structures_Guava_Javolution_Trove4j - Fatal编程技术网

Java 需要一个在添加和删除时不会产生任何垃圾的高效映射或集

Java 需要一个在添加和删除时不会产生任何垃圾的高效映射或集,java,data-structures,guava,javolution,trove4j,Java,Data Structures,Guava,Javolution,Trove4j,因此,由于Javolution不起作用(),我非常需要一个高效且在简单使用下不会产生垃圾的Java映射实现java.util.Map在添加和删除键时会产生垃圾。我检查了Trove和Guava,但看起来它们没有设置实现。在哪里可以找到java.util.Map的简单高效的替代方案 为EJP编辑: 添加条目时分配条目对象,删除条目时释放到GC:( void addEntry(整数散列、K键、V值、整数bucketinex){ 条目e=表[bucketIndex]; 表[bucketIndex]=新条

因此,由于Javolution不起作用(),我非常需要一个高效且在简单使用下不会产生垃圾的Java映射实现
java.util.Map
在添加和删除键时会产生垃圾。我检查了Trove和Guava,但看起来它们没有设置实现。在哪里可以找到
java.util.Map
的简单高效的替代方案

为EJP编辑:

添加条目时分配条目对象,删除条目时释放到GC:(

void addEntry(整数散列、K键、V值、整数bucketinex){
条目e=表[bucketIndex];
表[bucketIndex]=新条目(散列、键、值、e);
如果(大小+>=阈值)
调整大小(2*表格长度);
}

一个选项是尝试修复HashMap实现以使用一个条目池。我已经这样做了。:)还有其他优化速度的方法。我同意你的看法:Javolution FastMap的问题令人难以置信(

从字面上看,我不知道任何现有的Map或Set实现,在添加和删除密钥时不会产生任何垃圾

事实上,这在技术上是唯一可行的方法(在Java中,使用定义的
Map
Set
API)如果要对条目数设置严格的上限。实际的Map和Set实现需要与它们所持有的元素数成比例的额外状态。此状态必须存储在某个位置,并且当超过当前分配时,需要扩展该存储。在Java中,这意味着需要分配新节点艾德

(好的,您可以设计一个数据结构类,它永远保存在旧的无用节点上,因此从不生成任何可收集的垃圾……但它仍然在生成垃圾。)


因此,在实践中,您可以对此做些什么……以减少生成的垃圾量。让我们以
HashMap
为例:

  • 删除条目时会创建垃圾。这是不可避免的,除非您用一个永远不会释放表示链条目的节点的实现来替换哈希链。(这是一个坏主意……除非您可以保证空闲节点池的大小始终很小。请参阅下文了解这是一个坏主意的原因。)

  • 调整主哈希数组的大小时会创建垃圾。可以通过以下几种方式避免此情况:

    • 您可以在HashMap构造函数中提供一个“capacity”参数,将初始哈希数组的大小设置为足够大,这样您就不需要调整它的大小。(但这可能会浪费空间……特别是当您无法准确预测
      HashMap
      将增长多大时。)

    • 您可以为'load factor'参数提供一个荒谬的值,以使HashMap永远不会调整自身大小。(但这会导致HashMap的哈希链是无界的,并且您最终会出现查找、插入、删除等
      O(N)
      行为。)


事实上,创建垃圾并不一定对性能有害。事实上,挂起节点使垃圾收集器不收集它们实际上会对性能有害

GC运行的成本(假设使用现代复制收集器)主要有三个方面:

  • 查找不是垃圾的节点
  • 将这些非垃圾节点复制到“到空间”
  • 更新其他非垃圾节点中的引用以指向“到空间”中的对象
(如果您使用的是低暂停收集器,那么还有其他成本……通常与非垃圾量成比例。)

GC工作的唯一部分实际上取决于垃圾量,是将垃圾对象曾经占用的内存归零,以使其为重用做好准备。这可以通过对整个“来自空间”的单个
bzero
调用或使用虚拟内存技巧来完成

假设您的应用程序/数据结构挂起到节点上以避免创建垃圾。现在,当GC运行时,它必须做额外的工作来遍历所有这些额外的节点,并将它们复制到“到空间”,即使它们不包含任何有用的信息。此外,这些节点正在使用内存,这意味着如果应用程序的其余部分生成垃圾,则容纳垃圾的空间将减少,并且GC将需要更频繁地运行

如果您使用弱/软引用来允许GC从您的数据结构中回迁节点,那么对于GC来说,这将是更多的工作……以及表示这些引用的空间

注意:我并不是说对象池总是让性能变差,只是它经常会这样,特别是当池变得出乎意料的大时

当然,这就是为什么HashMap和类似的通用数据结构类不做任何对象池的原因。如果它们做了,那么在程序员没有预料到的情况下,它们的性能将非常糟糕……而且它们将真正被破坏,依我看



最后,有一种简单的方法可以优化HashMap,以便在添加后立即删除同一个键不会产生垃圾(保证)。将其包装在一个Map类中,该类缓存最后一个条目“added”,并且只有在添加下一个条目时,
才会将
放在真正的
HashMap
上。当然,这不是一个通用的解决方案,但它确实解决了您前面问题的用例。

我想您需要一个使用开放寻址的HashMap版本,您会想要比线性探测更好的东西。我不知道但是有一个特定的建议。

有Set和Map的实现,它们不会在添加或删除键时创建垃圾。该实现使用具有交替键和值的单个数组,因此put(k,v)不会创建条目对象

现在,有一些警告:
   void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }