阅读后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 有一个 patent在
byte[]
字符串的表示,据我所知。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 question和 its accepted answer .现在这个选项似乎已经死了。这在错误 7129417 中得到了进一步证实。报告。
目的证明手段
警告: (丑)针对特定需求的解决方案
这有点开箱即用,级别较低,但既然你问了......不要打信使!
你自己的打火机字符串表示
如果 ASCII 可以满足您的需求,那么您为什么不推出自己的实现呢?
正如你提到的,你可以
byte[]
而不是 char[]
内部。但这还不是全部。为了做得更轻量级,与其将字节数组包装在一个类中,为什么不简单地使用一个包含主要静态方法的辅助类,这些方法对您传递的这些字节数组进行操作?当然,它会感觉很C-ish,但它会起作用,并且会为您节省巨大的与
String
相关的开销对象。当然,它会错过一些不错的功能……除非您重新实现它们。如果你真的需要它们,那么没有太多选择。感谢 OpenJDK 和许多其他好的项目,你可以很好地推出自己的 fugly
LiteStrings
仅在 byte[]
上运行的类参数。每次需要调用函数时,您都会感觉像是在洗澡,但您会节省大量内存。我建议让它与
String
非常相似类的契约,并提供有意义的适配器和构建器来相互转换 String
,并且您可能还希望拥有往返于 StringBuffer
的适配器。和 StringBuilder
,以及您可能需要的其他东西的一些镜像实现。绝对是一些工作,但可能是值得的(请参阅下面的“让它算数!”部分)。即时压缩/解压缩
您可以很好地在内存中压缩字符串,并在需要时即时解压缩它们。毕竟,您只需要在访问它们时才能读取它们,对吗?
当然,如此暴力意味着:
两者都做
对于完全头痛,当然你可以做所有这些:
一定要把它开源。 :)
让它计数!
顺便说一下,请参阅 上的精彩演示文稿构建内存高效的 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/