2012-12-31 129 views
5

我在写一些需要在内存中保存大量数据的“大数据”软件。我用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中具有讨厌的比例开销。

+3

totalMemory还包含空闲内存,请尝试使用totalMemory()来测量 - freeMemory() – Henry

+0

如果您想要一个非常准确的数字,请使用应用程序的堆转储并使用Memory Analyzer(http ://www.eclipse.org/mat/)以获得准确的数字。 2nd - 这个数据的访问模式是什么?也许你可以通过使用一些可以将未使用的部分分页到磁盘的缓存库来获得更多的空间?说你的点分成10K项目的数组,并将这些“块”存储在infinispan(http://www.jboss.org/infinispan/)或类似的? – radai

+0

@亨利好点!使用totalMemory()进行测量 - freeMemory()为每个结构提供36个字节的值。优于52,但仍是C++的2倍。 – andyInCambridge

回答

2

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

VisualVM的截图显示性能轨迹(从http://visualvm.java.net/features.html图像): enter image description here

你也应该考虑做最后的变量,如果有可能。它允许Java VM更好地优化代码位(不知道它是否节省了空间)。

+0

让他们最终成为一个好主意。只是测试过它,不会改变内存占用。 – andyInCambridge

0

首先在Java所有对象的永远是从1995年起的对象C++版本稍大封装,使你做instanceof等是不可能在C++运行时类型信息。此外,它有助于在内存管理中手动完成自己的工作,因此您还可以将代码的这部分视为代码库的一部分。

您可以查看Flyweight Pattern以减少内存需求,以便重复使用DataPoints(使类Immutable)。我假设,如果你有几十亿分,如你所说,有些可能是相同的价值观。
我相信这里的其他人会给出一些关于优化内存空间的更多具体信息

0

根据值范围,您可以使用较小的数据类型。你可以避开使用字节或简短的一些成员?