【问题标题】:Why my JDBC call is consuming memory 4 times more that actual size of data为什么我的 JDBC 调用消耗的内存是实际数据大小的 4 倍
【发布时间】:2013-05-09 12:32:50
【问题描述】:

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

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

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

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

【问题讨论】:

  • Java 中的字符串使用 UTF-16,这意味着每个字符 2 个字节。因此,如果您的 txt 文件是正常的 8 位/字符编码,则会导致那里的 ram 使用率加倍。另外,如果使用 substring 方法,请记住,只要 substring 对象还活着,原始字符串 newer 就会被释放。
  • 感谢您的评论。是否有可能指示 JVM 使用 UTF-8 编码?
  • 不是直接的。 java.lang.String 将始终使用 UTF-16。但我确信谷歌搜索可以给你一个 java 字符串类,它使用 utf-8 或其他 8 位编码。
  • 是的,非常感谢,在搜索了一段时间后,我在这里找到了一个 vmoption -XX:+UseCompressedStrings (oracle.com/technetwork/java/javase/tech/…),它表示在字符串中使用了 byte[]。通过使用这个选项,我可以看到大约 500MB 的内存改进。
  • 这里真正的问题是为什么要将 5200 万行加载到内存中。这是一种糟糕的做法,并且鉴于数据的增长,它迟早会完全停止工作。一次处理一行。

标签: java jdbc


【解决方案1】:

这里没有什么奇怪的(至少对我来说)。

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

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

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

【讨论】:

    【解决方案2】:

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

    当然有可能的优化:

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

    以下主要是基于经验意见。我一般使用 4 个语言级别:

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

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

    【讨论】:

      猜你喜欢
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 2021-12-03
      • 1970-01-01
      相关资源
      最近更新 更多