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

java.lang.String是否有内存效率高的替代品?,java,string,optimization,memory,performance,Java,String,Optimization,Memory,Performance,在阅读了对几种对象类型的内存消耗的测量之后,我惊奇地发现Java中使用了多少内存Strings: length: 0, {class java.lang.String} size = 40 bytes length: 7, {class java.lang.String} size = 56 bytes 虽然这篇文章提供了一些减少这种情况的技巧,但我并不觉得它们完全令人满意。使用char[]存储数据似乎是浪费。大多数西方语言的明显改进是使用byte[]和类似UTF-8的编码,因为您只需要一个字

在阅读了对几种对象类型的内存消耗的测量之后,我惊奇地发现Java中使用了多少内存
String
s:

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”)
newstring(bytes,“UTF-8”)
。甚至字符串实例本身的开销也将消失。但是在那里你会失去一些非常方便的方法,比如
equals()
hashCode()
length()

据我所知,Sun有一个on
byte[]
字符串表示

用于在Java编程环境中高效表示字符串对象的框架 ... 在适当的情况下,可以实现这些技术来将Java字符串对象创建为单字节字符数组

但我没能找到该专利的API

我为什么在乎?
在大多数情况下,我没有。但是我在使用包含大量字符串的巨大缓存的应用程序上工作,这将从更有效地使用内存中获益

有人知道这样的API吗?或者,有没有其他方法可以让字符串的内存占用保持较小,即使以牺牲CPU性能或更丑陋的API为代价

请不要重复上述文章中的建议:

  • String.intern()
    的自有变体(可能与
    SoftReferences
  • 存储单个
    char[]
    并利用当前的
    String.subString(.)
    实现来避免数据复制(讨厌)
更新


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

出于好奇,节省的几个字节真的值得吗

通常,出于性能原因,我建议放弃字符串,而选择StringBuffer(请记住,字符串是不可变的)


你真的在用字符串引用耗尽堆吗?

只要用gzip压缩它们就行了。:)只是开玩笑。。。但我看到了一些奇怪的事情,它将以显著的CPU开销提供更小的数据

我所知道的唯一其他字符串实现是Javolution类中的实现。不过,我不认为它们的内存效率更高:



我认为你应该非常谨慎,不要根据2002年的一篇javaworld.com文章提出任何想法和/或假设。从那以后的六年中,编译器和JVM发生了很多很多变化。至少,首先用现代JVM测试您的假设和解决方案,以确保该解决方案是值得的。

我认为字符串在一段时间内内存占用较少,因为Java工程师已经实现了flyweight设计模式,以尽可能多地共享。
事实上,我相信具有相同值的字符串指向内存中非常相同的对象。

您说过不要重复文章中关于推出您自己的实习计划的建议,但是
String.intern
本身有什么问题?这篇文章包含以下一次性评论:

有许多原因可以避免使用String.intern()方法。一个是,很少有现代JVM能够实习大量数据

但是,即使2002年的内存使用率数据在六年后仍然保持不变,如果JVM可以占用多少数据方面没有取得任何进展,我也会感到惊讶


这不是一个纯粹的修辞问题——我想知道是否有充分的理由避免它。对于高度多线程的使用,它的实现是否效率低下?它是否填充了堆中特定于JVM的特定区域?你真的有数百兆字节的唯一字符串吗(因此,不管怎么说,插入都是无用的)?

创建一个对象(至少是一个调度表)会有开销,每个字母使用2个字节的开销,还有一些额外变量的开销,这些额外变量实际上是为了在许多情况下提高速度和内存使用率而创建的

如果您打算使用OO编程,这就是拥有清晰、可用、可维护代码的成本

除了显而易见的答案(如果内存使用如此重要,您可能应该使用C),您还可以使用BCD字节数组中的内部表示实现自己的字符串

这听起来很有趣,我可能只是为了好玩:)

Java数组每项占用2字节。BCD编码的数字每字母IIRC占用6位,使字符串大大减小。在时间上会有一点转换成本,但实际上并不太糟糕。真正的大问题是,你必须转换成字符串来处理它

您仍然需要担心对象实例的开销。。。但是,通过改进您的设计,而不是试图消除实例,可以更好地解决这一问题

最后是一张纸条。我完全反对部署这样的东西,除非你有三件事:

  • 以最具可读性的方式完成的实现
  • 测试结果和需求表明实现如何不满足需求
  • 关于“改进的”实现如何满足需求的测试结果

如果没有这三个方面,我会放弃开发人员提供给我的任何优化解决方案。

Java选择UTF-16是为了兼顾速度和存储大小。处理UTF-8数据比处理UTF-16数据要复杂得多(例如,当试图在字节数组中查找字符X的位置时,如果每个字符
-XX:+UseCompressedStrings