5

我正在编写一些需要在内存中保存大量数据的“大数据”软件。我用 C++ 写了一个原型,效果很好。然而,实际的最终用户通常使用 Java 编写代码,因此他们要求我也编写一个 Java 原型。

我已经完成了关于 java 内存占用的背景阅读和一些初步测试。例如,假设我有这个对象

public class DataPoint{

    int cents, time, product_id, store_id;

    public DataPoint(int cents, int time, int product_id, int store_id){
    this.cents = cents;
    this.time = time;
    this.product_id = product_id;
    this.store_id = store_id;
    }
}

在 C++ 中,这个结构的大小是 16 字节,这是有道理的。在 Java 中,我们必须是间接的。例如,如果我创建 10m 的这些对象并在前后使用 Runtime.totalMemory() - Runtime.freeMemory(),然后根据需要进行划分,我得到每个结构大约 36 个字节。大约 2.4 倍的内存差异非常糟糕;当我们试图在内存中保存数亿个数据点时,它会变得丑陋。

我在某处读到,在 Java 中的这种情况下,最好将数据存储为数组——本质上是基于列的存储而不是基于行的存储。我想我理解这一点:基于列的方式减少了引用的数量,也许 JVM 甚至可以智能地将 int 打包成 8 字节的单词。

我可以使用哪些其他技巧来减少本质上是一个内存块的内存占用量,该内存块具有一个非常大的维度(数百万/十亿个数据点)和一个非常小的维度(O(1) 列/变量数)?

结果将数据存储为 4 个 int 数组,每个条目正好使用 16 个字节。教训:小对象在 java 中具有令人讨厌的比例开销。

4

3 回答 3

2

在 Java 中查看数据结构占用了多少内存并不是那么简单。totalMemory() 显示分配给 vm 的空间大于实际使用量。您可以尝试使用 Java 分析器来显示数据结构的空间消耗,它们很容易设置和运行。一个方便的免费工具是 Java 自己的VisualVM,例如显示应用程序的内存行为,如果您使用它,您还将了解 Java 的 GC 是如何工作的。

显示性能足迹的 VisualVM 屏幕截图(图片来自http://visualvm.java.net/features.html): 在此处输入图像描述

如果可能,您还应该考虑将变量设为最终变量。它允许 Java VM 更好地优化代码(虽然不确定它是否节省空间)。

于 2012-12-31T16:42:46.123 回答
0

首先,in 中的对象Java总是比版本稍大,C++因为对象封装了运行时类型信息,使您能够instanceof执行C++. 此外,它还有助于您必须自己手动进行的内存管理,因此您也可以将这部分C++代码视为代码库的一部分。

您可以查看享元模式以减少内存需求,以便重用DataPoints(使类Immutable)。我假设如果你说的有数十亿个点,有些可能是相同的值。
我相信这里的其他人会提供一些关于优化内存空间的更具体的信息

于 2012-12-31T16:42:49.650 回答
0

根据值范围,您可能可以使用较小的数据类型。您可以对某些成员使用 byte 或 short 吗?

于 2012-12-31T16:50:52.877 回答