我正在编写一些需要在内存中保存大量数据的“大数据”软件。我用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倍的内存差异非常讨厌;当我们试图在内存中保存数亿个DataPoints时,它会变得丑陋。
我在某处读过,在Java中这样的情况下,最好将数据存储为数组 - 实质上是基于列的存储而不是基于行的存储。我想我理解这一点:基于列的方式减少了引用数量,也许JVM甚至可以智能地将整数打包成8字节的字。
我可以使用哪些其他技巧来减少内存占用的内存占用内存块,该内存块具有一个非常大的维度(数百万/数十亿的数据点)和一个非常小的维度(O(1)列数/变量)?
结果将数据存储为4个int数组,每个条目恰好使用16个字节。经验教训:小对象在java中具有令人讨厌的比例开销。
答案 0 :(得分:2)
查看数据结构在Java中占用多少内存并不是那么简单。 totalMemory()显示为vm分配的空间,该空间大于实际使用情况。您可以尝试使用显示数据结构空间消耗的Java分析器,它们很容易设置和运行。一个方便的免费工具是Java自己的VisualVM,例如显示应用程序的内存行为,如果使用它,您还将学习Java的GC如何工作。
显示性能足迹的VisualVM屏幕截图(来自http://visualvm.java.net/features.html的图像):
如果可能的话,你还应该考虑让变量最终。它允许Java VM更好地优化代码位(不确定它是否可以节省空间)。
答案 1 :(得分:0)
首先,Java
中的对象将始终略大于C++
版本,因为该对象封装了运行时类型信息,使您可以执行instanceof
等不可能的操作C++
。此外,它还有助于您自己手动执行的内存管理,因此您也可以将C++
代码的这一部分视为代码库的一部分。
您可以查看Flyweight Pattern以减少内存需求,以便重复使用DataPoints
(使类Immutable)。我假设如果你有数十亿分,你说有些可能是相同的值
我相信这里的其他人会提供一些关于优化内存空间的更具体的信息
答案 2 :(得分:0)
根据值范围,您可以使用较小的数据类型。对于某些成员,你可以使用byte或short吗?