我在写一些需要在内存中保存大量数据的“大数据”软件。我用C++编写了一个很好的原型。然而,实际的最终用户通常使用Java编码,因此他们要求我也编写一个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中,我们必须是间接的。如果我创建了这些对象(例如,10米),并在 之前使用Runtime.totalMemory() - Runtime.freeMemory(),然后根据需要进行划分,则每个结构将获得大约36个字节。一个~2.4倍的内存差异是非常讨厌的;当我们试图在内存中保存数以亿计的数据点时,它会变得很难看。
我在某处读到,在Java这种情况下,它更好地将数据存储为数组 - 实质上是基于列的存储而不是基于行的存储。我想我明白这一点:基于列的方式减少了引用的数量,并且JVM甚至可以智能地将这些字符串打包成8字节的字。
还有什么其他的技巧可以用来减少本质上是一个非常大的维度(数百万/数十亿个数据点)和一个非常小的维度(O(1)列数量的内存块的内存占用/变量)?
结果将数据存储为每个条目恰好使用16个字节的4个int数组。教训:小的对象在java中具有讨厌的比例开销。
totalMemory还包含空闲内存,请尝试使用totalMemory()来测量 - freeMemory() – Henry
如果您想要一个非常准确的数字,请使用应用程序的堆转储并使用Memory Analyzer(http ://www.eclipse.org/mat/)以获得准确的数字。 2nd - 这个数据的访问模式是什么?也许你可以通过使用一些可以将未使用的部分分页到磁盘的缓存库来获得更多的空间?说你的点分成10K项目的数组,并将这些“块”存储在infinispan(http://www.jboss.org/infinispan/)或类似的? – radai
@亨利好点!使用totalMemory()进行测量 - freeMemory()为每个结构提供36个字节的值。优于52,但仍是C++的2倍。 – andyInCambridge