提高处理具有 1 亿个元素的 ArrayList 时的速度和内存消耗

2024-02-04

我使用其中包含短字符串(10 位数字)的文本文件。文件大小约为1.5Gb,因此行数达到1亿行。

每天我都会收到另一个文件,需要提取新元素(每天数万个)。

解决我的问题的最佳方法是什么?

我尝试在 ArrayList 中加载数据 - 每个文件大约需要 20 秒,但数组的减法需要很长时间。

我使用这段代码:

dataNew.removeAll(dataOld);

尝试在 HashSet 中加载数据 - HashSet 的创建是无止境的。 LinkedHashset 也是如此。

尝试加载到 ArrayList 中并仅对其中之一进行排序

Collections.sort(dataNew);

但并没有加快这个进程

dataNew.removeAll(dataOld);

而且内存消耗相当高 - sort() 仅用 15Gb 的堆完成(13Gb 是不够的)。

我尝试使用旧的 linux util diff,它在 76 分钟内完成了任务(同时消耗了 8Gb 的 RAM)。

因此,我的目标是在 1 小时的处理时间(当然或更短)内解决 Java 中的问题,消耗 15Gb(或更好 8-10Gb)。

请问有什么建议吗? 也许我不需要 ArrayList 的字母顺序排序,而是其他东西?

UPDATE:这是全国范围内无效护照的清单。它是作为全局列表发布的,所以我需要自己提取delta。

数据未排序,每行都是唯一的。所以我必须将 100M 元素与 100M 元素进行比较。数据线例如“2404,107263”。无法转换为整数。

有趣的是,当我将最大堆大小增加到 16Gb 时

java -Xms5G -Xmx16G -jar utils.jar

加载到 HashSet 变得很快(第一个文件需要 50 秒),但程序会被系统内存不足杀手杀死,因为它在将第二个文件加载到第二个 HashSet 或 ArrayList 时会消耗大量 RAM

我的代码很简单:

List<String> setL = Files.readAllLines(Paths.get("filename"));
HashSet<String> dataNew = new HashSet<>(setL);

在第二个文件上,程序得到

Killed

[1408341.392872]内存不足:杀死进程20538(java)分数489或牺牲孩子 [1408341.392874]杀死进程20531(java)total-vm:20177160kB,anon-rss:16074268kB,file-rss:0kB

UPDATE2:

感谢您的所有想法!

最终解决方案是:使用fastutil库(LongOpenHashSet)将行转换为Long +

RAM 消耗变为 3.6Gb,处理时间仅 40 秒!

有趣的观察。虽然使用默认设置启动 java 会导致无休止地加载 1 亿个字符串到 JDK 的本机 HashSet(我在 1 小时后中断),但从 -Xmx16G 开始将过程加速到 1 分钟。但内存消耗非常可笑(大约 20Gb),处理速度相当不错 - 2 分钟。

如果不受 RAM 限制,原生 JDK HashSet 在速度方面还不错。

附注也许这项任务没有明确解释,但我没有看到任何机会不完全加载至少一个文件。因此,我怀疑内存消耗是否可以进一步降低很多。


首先,不要做Files.readAllLines(Paths.get("filename"))然后将所有内容传递给Set,其中包含不必要的大量数据。任何时候尽量少排队。

逐行读取文件并进行处理。这会立即减少你的内存使用量。

Set<String> oldData = new HashSet<>();
try (BufferedReader reader = Files.newBufferedReader(Paths.get("oldData"))) {
    for (String line = reader.readLine(); line != null; line = reader.readLine()) {
        // process your line, maybe add to the Set for the old data?
        oldData.add(line);
    }
}

Set<String> newData = new HashSet<>();
try (BufferedReader reader = Files.newBufferedReader(Paths.get("newData"))) {
    for (String line = reader.readLine(); line != null; line = reader.readLine()) {
        // Is it enough just to remove from old data so that you'll end up with only the difference between old and new?
        boolean oldRemoved = oldData.remove(line);
        if (!oldRemoved) {
            newData.add(line);
        }
    }
}

您最终将得到两个集合,分别仅包含旧数据集中存在的数据或新数据集中存在的数据。

其次,如果可能的话,尝试预先调整容器的大小。当它们达到其容量时,它们的大小(通常)会加倍,这在处理大集合时可能会产生大量开销。

另外,如果您的数据是数字,您可以使用long并持有它,而不是试图持有实例String?有很多集合库可以让您做到这一点,例如Koloboke、HPPC、HPPC-RT、GS Collections、fastutil、Trove。甚至他们的收藏Objects作为标准可能会很好地为您服务HashSet有很多不必要的对象分配。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

提高处理具有 1 亿个元素的 ArrayList 时的速度和内存消耗 的相关文章

随机推荐

  • 作为 Android .apk 一部分的 Pdf 文件

    我必须构建一个 Android 应用程序来显示 pdf 文件列表 这些 pdf 文件应该受到保护 换句话说 应用程序的用户不应该能够通过任何方式 复制 剪切 打印 等 获取 pdf 内容的副本 我现在的问题是 我应该如何将 pdf 文件的内
  • 使用正则表达式标记字符串中的文本但排除链接

    我有一个文本 我希望当用户搜索某个术语时 通过用标记标签包裹该术语来突出显示该术语 javascript 来包装匹配项 var sampleText window document getElementById test innerHTML
  • java - 使用基类实例在派生类中访问受保护的成员

    我在派生类中创建了基类的实例并尝试访问受保护的成员 我可以直接访问派生类中的受保护成员 而无需实例化基类 基类 package com core public class MyCollection protected Integer int
  • 尝试在 Windows Phone 开发中心更新 XAP 时出错

    我正在尝试提交 Windows Phone 应用程序的更新 但是当我单击 更新应用程序 并选择相应的 xap 文件时 出现以下错误消息 ScriptObject InvokeFailed 参数 调试资源字符串不可用 通常 键和参数提供了足够
  • JSON 编码/解码 GTK 枚举

    我必须将自定义 GTK 元素的各种属性保存到文件中以供将来使用 并由于简单的格式和字典嵌套而决定使用 JSON 许多属性都是 GTK 枚举 例如gtk PAGE ORIENTATION PORTRAIT gtk ANCHOR CENTER
  • C 中的整数溢出:标准和编译器

    感谢 Carl Norum 的编辑 以包含正确的标准参考 C 标准规定 If an 特殊情况发生在表达式求值期间 即 如果结果未在数学上定义或不在其类型的可表示值范围内 则行为未定义 是否有编译器开关可以保证整数溢出时的某些行为 我想避免鼻
  • 如何取消定义或删除 JavaScript 函数?

    我定义了一个全局 Javascript 函数 function resizeDashBoardGridTable gridID var table document getElementById treegrid gridID 在使用这个函
  • 是否有一种标准方法来为 Java EE 容器定义 JDBC 数据源?

    我知道对于 JBoss 您需要在相应实例的 deploy 子目录中有一个 name ds xml 文件 我没有任何使用其他 Java EE 容器的经验 但我试图尽可能遵守标准 是否有定义 JDBC 数据源并部署它的标准方法 如果可能的话 我
  • 外部内联函数会发生什么?

    如果我在 h 文件中将函数定义为 extern int returnaint void 在相关的 c 文件中将其定义为 inline int returnaint void return 1 并将标头包含在另一个 c 文件中并使用该函数 当
  • 适用于 html5 和 jquery 应用程序的条码扫描器

    我正在一个项目中使用 Jquery 和 html 它是一个静态 Web 应用程序 我需要一个 jquery 来读取产品中条形码扫描仪的条形码 需要扫描条形码而不在屏幕的任何文本框中显示代码 有人请给我一些想法或为我提供插件的链接 如果有 来
  • PHP 中 C# 的“List ”等价物是什么?

    我正在使用一个 API 它要求我提供一个List
  • EF Code First:使用 Fluent API 映射非表对象

    我应该如何使用 Fluent API 映射 EF Code First 中的重要对象 例如视图 StoredProcedure 等 代码优先中尚不支持映射到存储过程和 vew 这些是 Julia Lerman 的编程实体框架 代码优先的一些
  • 带有两个 ArrayList 的 Android ListView 适配器

    In our chat app we want to use cool new Library SQLBrite https github com square sqlbrite to update chat on database cha
  • 未找到特征“Illuminate\Foundation\Auth\Access\AuthorizesResources”

    有人熟悉我遇到的这个错误吗 请帮忙谢谢 如果您使用 Laravel 5 3 请执行以下操作 来自升级指南 AuthorizesResources Trait AuthorizesResources 特征已与 AuthorizesReques
  • VS 2012 / 2013 AccessViolationException

    当我运行项目 F5 时 我在 IDE 中收到以下异常 An unhandled exception of type System AccessViolationException occurred in System Windows For
  • 仅包含单个 mp4 文件的 MPEG-DASH 视频流

    我研究了一周 寻找一种简单且独立于平台的方法 将 mp4 文件传输到任何浏览器 如果浏览器不兼容 将使用渐进式流 直接下载 方法 我的场景是这样的 单个 mp4 文件 未分段和复用 音频 视频 支持 HTTP 字节范围服务 在浏览器不兼容的
  • Android studio 重命名包后抛出 Nomatching client found

    我按照下面的链接重命名了包 重命名后 当我尝试构建项目时 android studio 会抛出类似的错误 Android Studio重命名包 https stackoverflow com questions 16804093 andro
  • 多个if条件excel,矩阵结构

    Box type Box type Box type Box type BinLoc 810 811 911 822 S1 2 0 1 0 S2 4 2 2 1 S3 12 6 6 3 S4 24 12 12 6 R1 48 24 24 1
  • Akka 消息传递保证

    我正在尝试找出 Akka 支持哪些消息传递保证 我得出以下结论 最多一次 默认支持 至少一次 由 Akka Persistence 支持 恰好一次 Akka支持exactly once吗 如果不这样做 我怎样才能实现这一目标 正如您所发现的
  • 提高处理具有 1 亿个元素的 ArrayList 时的速度和内存消耗

    我使用其中包含短字符串 10 位数字 的文本文件 文件大小约为1 5Gb 因此行数达到1亿行 每天我都会收到另一个文件 需要提取新元素 每天数万个 解决我的问题的最佳方法是什么 我尝试在 ArrayList 中加载数据 每个文件大约需要 2