【问题标题】:Adding to a large Java collection, performance bottleneck添加到大型 Java 集合,性能瓶颈
【发布时间】:2012-08-22 21:45:40
【问题描述】:

我正在尝试将一百万个对象添加到列表中。完成它所需的时间比我有耐心等待的时间长。似乎每一步都需要越来越长的时间。

    int size = 1000000;
    Deque<DatastoreElement> content = new LinkedList<DatastoreElement>();

    for (int i = 0; i < size; i++) {

        String k = Utils.getRandomStringOfLength(20);
        String v = Utils.getRandomStringOfLength(300); // goes faster with smaller number

        int metaHash = random.nextInt(10) + 1;
        KVPair kvp = new KVPair(k, v);
        DatastoreElement dse = new DatastoreElement(metaHash, kvp);

        content.addLast(dse); // confirmed problem is here

        if (i % 10000 == 0) {
            System.out.println(i);
        }
    }

我尝试向ListSet 添加内容,结果非常相似。它启动很快,然后在某个数字后窒息。

我应该使用什么集合来存储大量相似的元素?我在这里遗漏了一些简单的东西吗?

【问题讨论】:

  • 尝试为 1,000,000 个元素预分配 ArrayList
  • 答案取决于您打算如何使用这些数据。除非您需要能够在两个方向上进行迭代,否则请使用 ArrayList 而不是 LinkedList。加载完数百万个对象后,您将如何处理它们?
  • 也许 JVM 正在破坏。尝试使用 -mx 增加内存限制
  • @Jam 我非常怀疑adding 元素到ArrayList 会导致严重的瓶颈。你确定瓶颈不在于制作对象本身吗?
  • @Jam 为了将问题归结为特定调用,我建议您尝试使用适当的分析器来分析您的代码,例如 JDK 附带的 JVisualVM

标签: java performance collections


【解决方案1】:

这个问题一般不存在于集合中,如图所示的LinkedList(具有O(1) 添加特征)。

因此,可能的嫌疑人是内存抖动/交换。 确保JVM有足够的内存,系统有更多..

LinkedList 切换到ArrayList(或ArrayDeque)将保持O(1) 摊销性能,但可能略有 > 每个项目的开销更少。 (开销,以及这种减少是否重要,取决于添加的对象的大小和后备存储的填充率。)

【讨论】:

  • 实际上LinkedList 总是会更糟,因为内存节点不是像ArrayList 那样可以缓存在相同页面中的连续内存
  • @Cratylus 这是 JVM 来处理的 :) 一个反例可能在填充率约为 50% 的“支持双倍”操作之后。但是如果没有一些测试,我不会以任何一种方式下注..
  • JVM?你认为JVM对大小为X的节点的请求做这些优化?
  • ArrayList 在内存局部性方面几乎肯定会比LinkedList 做得更好。
  • 现在使用简单数组,Xmx1024m。奇迹般有效。谢谢。
【解决方案2】:
  • ArrayList 已被建议(在链表中,每个项目/节点都意味着一个附加对象)。
  • 另外(之前也建议过),如果您使用基于数组的集合,请尝试将其构造/调整到足够的长度。
  • 另外,如果内存是个问题,您可能希望将享元模式与字符串元素 String#intern() 一起使用,这样可以收集冗余实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 2015-07-27
    • 1970-01-01
    • 2011-05-25
    • 2018-07-20
    • 1970-01-01
    相关资源
    最近更新 更多