将字符串封装为byte[]以节省内存是否过度设计?(Java)

7

最近我在审查一些Java Swing代码时看到了这个:

byte[] fooReference;

String getFoo() {
   returns new String(fooReference); 
}

void setFoo(String foo) {
  this.fooReference = foo.getBytes();
}

据称,以上方法可以帮助你节省内存空间。这种方式是否太过于繁琐?还有其他人会这样封装他们的字符串吗?


1
除非您正在存储数千兆字节或千兆字节的字符串,否则我甚至不会考虑这样做。 - Joe Phillips
8个回答

32

这是一个非常糟糕的想法,请勿使用平台默认编码。如果你调用 setFoo 然后再调用 getFoo ,就没有保证你能获得相同的数据。

如果你必须要这样做,那么请使用UTF-8编码,它能够表示Unicode的全部字符...但我真的不会这样做。这种做法可能会节省一些内存,但大多数时间都会进行不必要的转换,容易出现错误,因为可能无法使用适当的编码。

我敢说有一些应用程序可以采用这种方法,但对于99.99%的应用程序来说,这是个可怕的想法。


1
这还假设将其存储为字节并在每次访问时创建一个新字符串本身就是个好主意。 - Michael Myers
@mmyers:我正要说到那个 :) - Jon Skeet
可能他正在使用charset选项,但我记不清了 - 即使如此,这似乎是一个不受欢迎的想法。很高兴我问了。 - JARC

10

这并不是很有用:
1. 每次调用getFoo或setFoo时都会复制该字符串,因此增加了CPU和内存的使用
2. 它很难理解


5

一次小小的历史考察...

在 Java 早期(1.0/1.1),如果你能确保不需要使用 ISO-8859-1 以外的字符集,使用字节数组而非字符串对象实际上有一些相当大的优势。在那个时代的虚拟机中,使用 drawBytes() 要比使用 drawString() 快 10 倍以上,它实际上可以节省内存,而当时内存仍然非常稀缺,applet 的硬编码内存限制为 32 MB 或 64 MB。与嵌入式 char[] 相比,byte[] 更小,而且还可以节省相对较重的 String 对象本身,如果有很多短字符串,这会产生相当大的差异。此外,访问纯 byte 数组也比使用 String 的访问器方法更快,后者有额外的边界检查。

但是,自从 Java 1.2 后,drawBytes 不再比字符串快,而且当前的 JIT 比 Symantec JIT 好得多,因此字节数组相对于字符串的微小性能优势已经不值得麻烦了。内存优势仍然存在,因此在某些极端情况下仍可能是一个选择,但现在如果没有必要,就不应该考虑使用它。


3

这可能会有些过度,甚至会消耗更多的内存,因为现在你有了两个字符串副本。实际字符串的生命周期取决于客户端,但像许多这样的黑科技一样,它很像过早优化。


使用的情况是在Swing客户端缓存中。被告知在JTable中,这将节省内存。 - JARC

3

如果你预计会有很多相同的字符串,另一种更好的节省内存的方法是使用 String.intern() 方法。


2

这确实没有任何意义。如果它是一个编译时常量,你不需要将其转换为 String,那么它会更有意义。你仍然有字符编码问题。

如果它是一个 char[] 常量,那么对我来说会更有意义。在现实世界中,有几个 JSP 编译器可以将字符串常量优化成一个 char[],然后可以轻松地写入到 Writer#write(char[]) 中。最终这样会 "稍微" 更有效率,但在像 Google 搜索等大型和高度使用的应用程序中,这些小细节都很重要。

Tomcat 的 JSP 编译器 Jasper 也是这样做的。检查 genStringAsCharArray 设置。它会这样做:

static final char[] text1 = "some static text".toCharArray();

替代

static final String text1 = "some static text";

这样可以减少开销。它不需要一个完整的String实例来围绕这些字符。


2

每次调用getFoo()都会实例化一个新的String。这样怎么能节省内存呢?如果有什么问题,当这些新引用变得无引用时,你会为垃圾收集器增加额外的开销来清理这些新实例。


1
如果在对代码进行分析后,发现字符串的内存使用是一个问题,那么最好使用通用的字符串压缩器并存储压缩后的字符串,而不是尝试使用UTF-8字符串以获得微小的空间减少。对于英语字符串,您通常可以将它们压缩到每个字符1-2位;大多数其他语言可能类似。达到每个字符<1位是困难的,但如果您有大量数据,则有可能实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接