Java:填充内存中排序的批处理

标签 java memory-management heap-memory

所以我使用 Java 对以行分隔的元组的大型磁盘文件进行多路外部合并。成批的元组被读入 TreeSet,然后被转储到磁盘上排序的批处理中。一旦所有的数据都用完了,这些批处理就会被合并排序到输出中。

目前我正在使用魔数(Magic Number)来计算我们可以放入内存中的元组数量。这是基于一个静态图,该图表明每 MB 堆空间可以粗略地容纳多少元组,以及有多少堆空间可用:

long max = Runtime.getRuntime().maxMemory();
long used = Runtime.getRuntime().totalMemory();
long free = Runtime.getRuntime().freeMemory();      
long space = free + (max - used);

然而,这并不总是那么有效,因为我们可能正在对不同长度的元组进行排序(对此,每 MB 的静态元组数字可能过于保守),而我现在想使用享元模式在其中加入更多内容,这可能会使数字更加多变。

所以我正在寻找一种更好的方法来将堆空间填满。理想情况下,解决方案应该是:

  • 可靠(没有堆空间异常的风险)
  • 灵活(不基于静态数字)
  • 高效(例如,不在每个元组之后轮询运行时内存估计)

有什么想法吗?

最佳答案

由于垃圾收集器的垃圾处理,将堆填满可能不是一个好主意。 (当内存接近满时,垃圾收集的效率接近于 0,因为收集的努力取决于堆大小,但释放的内存量取决于识别为无法访问的对象的大小)。

但是,如果你必须这样做,难道你不能简单地按照下面的方式来做吗?

for (;;) {
    long freeSpace = getFreeSpace();
    if (freeSpace < 1000000) break;
    for (;;freeSpace > 0) {
        treeSet.add(readRecord());
        freeSpace -= MAX_RECORD_SIZE;
    }
}

发现空闲内存的调用很少见,因此不会对性能造成太大影响。例如,如果您有 1 GB 的堆空间,并留出 1MB 的空间,并且 MAX_RECORD_SIZE 是平均记录大小的十倍,则 getFreeSpace() 将被调用仅仅是一个 log(1000 )/-log(0.9) ~= 66 次。

关于Java:填充内存中排序的批处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6484944/

相关文章:

java - 什么是NullPointerException,我该如何解决?

c++ - std::unique_ptr 的高效内存自定义删除器?

c - GPU 上是否有内存保护

c++ - 在函数 B 中释放函数 A 的运行时内存

java - android应用程序中的堆空间

java - 带有 RecyclerView 和 CollapsingToolbarLayout 的 CoordinatorLayout

java - 馆藏 map

java - 以 .heapdump 文件格式打开堆转储

c++ - 您可以删除在堆上创建并由函数返回的数组吗?

elasticsearch - 如何在Centos 7中增加Elasticsearch的堆内存?