【发布时间】:2011-10-02 23:53:29
【问题描述】:
前段时间我在讨论字符串和各种语言,string interning 的话题出现了。显然,Java 和 .NET 框架会自动对所有字符串以及几种脚本语言执行此操作。从理论上讲,它可以节省内存,因为您最终不会得到同一个字符串的多个副本,并且它可以节省时间,因为字符串相等比较是一个简单的指针比较,而不是 O(N) 遍历字符串的每个字符。
但我想得越多,就越怀疑这个概念的好处。在我看来,优势主要是理论上的:
- 首先,要使用自动字符串暂留,所有字符串都必须是不可变的,这使得很多字符串处理任务比实际需要的更难。 (是的,我听过所有关于不变性的论点。这不是重点。)
- 每次创建新字符串时,都必须根据字符串实习表检查它,这至少是一个 O(N) 操作。 (编辑:其中 N 是字符串的大小,而不是表的大小,因为这让人们感到困惑。)因此,除非字符串相等比较与新字符串创建的比率相当高,否则它是节省的净时间不太可能是正值。
- 如果字符串相等表使用强引用,则字符串在不再需要时永远不会被垃圾回收,从而浪费内存。另一方面,如果表使用弱引用,则字符串类需要某种终结器来从表中删除字符串,从而减慢 GC 过程。 (这可能非常重要,具体取决于字符串实习生表的实现方式。在最坏的情况下,从哈希表中删除一个项目可能需要在某些情况下对整个表进行 O(N) 次重建。)
这只是我思考实现细节的结果。有什么我错过的吗?在一般情况下,字符串实习是否真的提供了任何显着的好处?
编辑 2: 好吧,显然我是从一个错误的前提出发。与我交谈的人从未指出弦乐实习对于新创建的弦乐是可选的,实际上给人的强烈印象是相反的情况。感谢 Jon 把事情弄清楚了。另一个接受他的答案。
【问题讨论】:
-
为什么你认为根据字符串实习表检查一个新字符串是一个 O(N) 操作?
-
有趣的问题。我不同意 O(N),因为实习生表可以是字典。
-
Java 并非对所有字符串都这样做 - 只是所有字符串 literals,可以在编译时确定并设置为类加载的一部分,因此几乎没有运行时间成本。新的 String 对象没有被实习;代码必须显式调用它们的 intern() 方法才能这样做。因此,您的代码可以决定实习是否适合其使用模式,并选择是否使用它。实习字符串池不算作强引用,因此不排除 GC。
-
我有一种感觉,很难说实习和不变性是鸡还是蛋。使字符串不可变是有原因的,这种实现的有用好处之一可能是实习,但这可能不是主要原因。
-
“O(N) 操作。(编辑:其中 N 是字符串的大小,而不是表格的大小,因为这让人感到困惑。)”。令人困惑是有原因的。字符串的长度很少适用于实习字符串,因为哈希只计算一次。大小无关紧要。
标签: java .net python ruby string-interning