5

我编写了一个小型 java 程序,它使用简单的 JDBC 调用从 DB2 数据库加载数据。我正在使用选择查询来获取数据并为此使用 java 语句。我已正确关闭语句和连接对象。我正在使用 64 位 JVM 进行编译和运行程序。

该查询返回 5200 万条记录,每行有 24 列,在 Unix(具有多处理器环境)中加载完整数据大约需要 4 分钟。我使用 HashMap 作为数据结构来加载数据:Map<String, Map<String, GridTradeStatus>>. bean GridTradeStatus是一个简单的getter/setter bean,其中包含24 个属性。

该程序所需的内存高得惊人。Java 堆大小高达 5.8 - 6GB 以加载完整数据,而实际使用的堆大小保持在 4.7 - 4.9GB 之间。我知道我们不应该将这么多数据加载到内存中,但我的业务需求只是这样。

问题是,当我将表的全部数据放在一个平面文件中时,它的大小大致相当于 ~1.2GB。我想知道为什么我的 java 程序消耗的内存是其实际大小的 4 倍。

4

2 回答 2

1

这里没有什么令人惊讶的(至少对我来说)。

a.) 与大多数常见文本格式相比,java 中的字符串占用的空间是双倍的(因为字符串在堆中始终表示为 UTF-16)。此外,String 作为一个对象有相当多的开销(String 对象本身、对它包含的 char[] 的引用、hashCode 等)。对于小字符串,String 对象很容易花费与其包含的数据一样多的内存。

b.) 你把东西放进一个HashMap。HashMap 并不完全是内存效率的。首先,它使用 75% 的默认负载因子,这意味着具有许多条目的地图也有一个大桶数组。然后,映射中的每个条目都是一个对象本身,它至少要花费两个引用(键和值)加上对象开销。

总之,您几乎必须期望内存需求会增加很多。如果您的平均数据字符串相对较短,则因子 4 是合理的。

于 2013-05-15T15:54:55.397 回答
0

如果您认为无法承受平面文件中的数据大小与在 HashMap 中加载字符串所需的内存之间的 1:4 比率,则应考虑不使用 Java,而是使用较低级别的语言,例如 C++ 甚至 C。

当然有可能的优化:

  • 使用byte[]代替String(大约一半大小)
  • 不要使用默认HashMap参数(初始大小/负载因子),而是调整它们以满足您的实际要求。

下面主要是经验基于意见。我通常使用 4 个语言级别:

  • 高级脚本语言(Python、Ruby 甚至 bash ...)当性能不是要求并且开发速度是
  • 中级语言(Java,不太常见的高级 C++),当性能很重要但我还想要简单的开发和健壮性(强类型,...)
  • 低级语言(低级 C++ 或 C)什么性能是高要求以及何时我接受花费更多时间编写和测试单个模块
  • 用于性能至关重要的小零件的汇编语言,并已通过分析证明了这一点。

恕我直言,您可以调整 Java 代码以大大减少内存占用,但您可能会因失去出色的字符串和集合支持而失去对 Java 的大部分兴趣。用 C++ 编写应用程序的一小部分代码并使用 JNI 将所有内容联系在一起可能更容易,也可能更有效。

于 2014-09-10T21:23:32.440 回答