java - java.lang.String 是否有内存高效的替代品?

标签 java string optimization memory performance

阅读后this old article测量几种对象类型的内存消耗,我惊讶地看到内存String在 Java 中使用:

length: 0, {class java.lang.String} size = 40 bytes
length: 7, {class java.lang.String} size = 56 bytes
虽然这篇文章有一些技巧可以最大限度地减少这种情况,但我发现它们并不完全令人满意。用char[]好像有点浪费用于存储数据。大多数西方语言的明显改进是使用 byte[]而是使用像 UTF-8 这样的编码,因为您只需要一个字节来存储最常用的字符,而不是两个字节。
当然可以用String.getBytes("UTF-8")new String(bytes, "UTF-8") .甚至 String 实例本身的开销也会消失。但是这样你就失去了非常方便的方法,比如 equals() , hashCode() , length() , ...
Sun 有一个 patentbyte[]字符串的表示,据我所知。

Frameworks for efficient representation of string objects in Java programming environments
... The techniques can be implemented to create Java string objects as arrays of one-byte characters when it is appropriate ...


但是我没有找到该专利的 API。
我为什么在乎?
大多数情况下我不会。但是我研究了具有大量缓存的应用程序,其中包含大量字符串,这将从更有效地使用内存中受益。
有人知道这样的API吗?或者是否有另一种方法可以让 Strings 的内存占用保持较小,即使以 CPU 性能或更丑陋的 API 为代价?
请不要重复以上文章中的建议:
  • String.intern() 的自己的变体(可能与 SoftReferences )
  • 存储单个 char[]并利用当前String.subString(.)避免数据复制的实现(讨厌)

  • 更新
    我运行了有关 Sun 当前 JVM (1.6.0_10) 的文章中的代码。它产生了与 2002 年相同的结果。

    最佳答案

    借助 JVM 的一点帮助...

    警告:此解决方案现在在较新的 Java SE 版本中已过时。请参阅下面的其他临时解决方案。

    如果您使用 HotSpot JVM,自 Java 6 更新 21 起,您可以使用以下命令行选项:

    -XX:+UseCompressedStrings
    

    JVM Options页面如下:

    Use a byte[] for Strings which can be represented as pure ASCII. (Introduced in Java 6 Update 21 Performance Release)



    更新 :此功能在更高版本中被破坏,应该在 Java SE 6u25 中再次修复,如 6u25 b03 release notes 所述(但是我们在 6u25 final release notes 中没有看到它)。 bug report 7016213出于安全原因不可见。因此,请谨慎使用并先检查。喜欢任何 -XX选项,它被认为是实验性的并且可能会在没有太多通知的情况下发生变化,因此在生产服务器的启动脚本中不使用它可能并不总是最好的。

    更新 2013-03 (感谢 Aleksey Maximus 的评论):看到这个 related questionits accepted answer .现在这个选项似乎已经死了。这在错误 7129417 中得到了进一步证实。报告。

    目的证明手段

    警告: (丑)针对特定需求的解决方案

    这有点开箱即用,级别较低,但既然你问了......不要打信使!

    你自己的打火机字符串表示

    如果 ASCII 可以满足您的需求,那么您为什么不推出自己的实现呢?

    正如你提到的,你可以 byte[]而不是 char[]内部。但这还不是全部。

    为了做得更轻量级,与其将字节数组包装在一个类中,为什么不简单地使用一个包含主要静态方法的辅助类,这些方法对您传递的这些字节数组进行操作?当然,它会感觉很C-ish,但它会起作用,并且会为您节省巨大的String 相关的开销对象。

    当然,它会错过一些不错的功能……除非您重新实现它们。如果你真的需要它们,那么没有太多选择。感谢 OpenJDK 和许多其他好的项目,你可以很好地推出自己的 fugly LiteStrings仅在 byte[] 上运行的类参数。每次需要调用函数时,您都会感觉像是在洗澡,但您会节省大量内存。

    我建议让它与 String 非常相似类的契约,并提供有意义的适配器和构建器来相互转换 String ,并且您可能还希望拥有往返于 StringBuffer 的适配器。和 StringBuilder ,以及您可能需要的其他东西的一些镜像实现。绝对是一些工作,但可能是值得的(请参阅下面的“让它算数!”部分)。

    即时压缩/解压缩

    您可以很好地在内存中压缩字符串,并在需要时即时解压缩它们。毕竟,您只需要在访问它们时才能读取它们,对吗?

    当然,如此暴力意味着:
  • 更复杂(因此不易维护)的代码,
  • 更多的处理能力,
  • 压缩需要相对较长的字符串才能相关(或通过实现您自己的存储系统将多个字符串压缩为一个,以使压缩更有效)。

  • 两者都做

    对于完全头痛,当然你可以做所有这些:
  • C-ish 辅助类,
  • 字节数组,
  • 即时压缩存储。

  • 一定要把它开源。 :)

    让它计数!

    顺便说一下,请参阅 上的精彩演示文稿构建内存高效的 Java 应用程序 作者:N. Mitchell 和 G. Sevitsky:[ 2008 version ], [ 2009 version ]。

    从本演示文稿中,我们看到 8 个字符的字符串占用 64 个字节 在 32 位系统上(64 位系统为 96 !!),其中大部分是由于 JVM 开销。从这个 article我们看到一个 8 字节数组将“仅”吃掉 24 字节 : 12 字节的 header ,8 x 1 字节 + 4 字节对齐)。

    如果你真的操作了很多东西,这听起来可能是值得的(并且可能会加快速度,因为你会花更少的时间分配内存,但不要引用我的话并对其进行基准测试;另外它会很大程度上取决于您的实现)。

    关于java - java.lang.String 是否有内存高效的替代品?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/231051/

    相关文章:

    database - 加入 varchar(50) 外键会减慢查询速度

    Python - 如何提高复杂递归函数的效率?

    java - FileOutputStream 仅在程序终止后才写入文件的错误

    java - 测试该文件已移动到 "processed"路由 ftp ://host/incoming? move=processed in Camel

    java - 定义要覆盖的方法

    c++ - 为什么 VC++ 字符串不被引用计数?

    java - JLabel 之上的 JButton

    c - 迭代动态分配的 char 数组

    php - 抓取 php 字符串中最后 "/"之后的剩余文本

    html - 浏览器是否加载隐藏 Assets