【问题标题】:java in-memory size optimizationjava内存大小优化
【发布时间】:2013-01-01 00:51:20
【问题描述】:

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

【问题讨论】:

  • totalMemory 也包括空闲内存,尝试用 totalMemory()-freeMemory() 测量
  • 首先,如果您想要一个真正准确的数字,请获取您的应用程序的堆转储并使用 Memory Analyzer (eclipse.org/mat) 之类的工具打开该转储以获得准确的数字。第二 - 对这些数据的访问模式是什么?也许您可以通过使用一些可以将未使用部分分页到磁盘的缓存库来获得更多空间?说将您的点分成 10K 项的数组并将这些“块”存储在 infinispan (jboss.org/infinispan) 或类似的?
  • @Henry 好点!使用 totalMemory()-freeMemory() 测量得出每个结构 36 字节的值。优于 52,但仍然是 C++ 的 2 倍以上。
  • @radai 访问模式是一次将所有数据保存在内存中,这样我们就可以运行简化的 SQL 类型的查询,这会使普通的 SQL 引擎爆炸。
  • 那么是的,尽可能地放弃 OO 伪装并使用 4 个巨大的 int 数组肯定会为您节省一些空间 - 假设您预先分配所有空间并且不必处理调整大小和碎片化。再加上享元模式,您甚至可以尝试假装它的 OO :-) 另外,如果您要使用数组,您是否可以确保在任何给定时刻加载的产品和商店少于 2^16 个,并使用更小的原语对于 store_id 和 product_id ?你可以有一个从较短的 temp_id 到真正的 32 位的查找表。

标签: java memory optimization


【解决方案1】:

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

VisualVM 屏幕截图显示性能占用(图片来自http://visualvm.java.net/features.html):

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

【讨论】:

  • 使它们成为最终版本是个好主意。刚刚测试过,但不会改变内存占用。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 2012-08-12
      • 2014-05-05
      • 2011-11-01
      • 2011-02-17
      相关资源
      最近更新 更多