3

我阅读了很多答案,但没有一个能真正准确地回答我的问题。

如果我有一个在某个端口上运行的 java 服务并且客户端连接到它并调用如下方法:

String data = getServiceData("clientKey");

现在我的问题是,这个键(clientKey)会存储在服务端的字符串文字池中吗?通常,要存储在常量池中的文字是在编译时计算出来的,但是从 JVM 外部传递的字符串或读取文件时可能会发生什么情况?

4

2 回答 2

3

字符串对象在您的客户端被序列化和反序列化并保存在堆内存中。如果您希望它存储在您的字符串池内存中,您应该使用intern()方法。

    String value;
    String data = (value =getServiceData("clientKey"))==null?null:value.intern();
于 2014-08-07T15:09:41.323 回答
2

大多数从外部源(尤其是 Java 序列化)读取字符串的方法BufferedReader.getLine()都不会对字符串进行实习,所以答案是否定的。

但是,如果您使用第三方库,他们可能会这样做:例如,已知有一些 XML/Dom 解析器可以这样做(至少对于元素名称,较少用于值)。对于某些字符串(例如 HTTP 标头名称),还有一些高性能框架(servlet 容器)。

但通常它很少用在好的(!)实现中,因为它不像人们想象的那样可取。不要忘记:在你可以实习之前,它必须作为一个无论如何都需要收集的对象存在,所以从避免垃圾使用的角度来看,intern()它没有帮助。如果这些字符串存活很长时间(它不在 OLTP 中),它只会减少工作集内存,并且可能会稍微加快相等性检查。但通常这仅在您对同一个字符串对象执行数千个操作时才有帮助。

您可以检查自己的字符串是否已经被实习(你当然不应该在生产代码中这样做,因为它实习你的字符串并且它可能不适用于所有实现):

input == input.intern()?"yes":"no"`

是的(如评论中所问),可能会发生数百万个相同 API 密钥的实例。但不要误以为这是一件坏事。实际上,实习他们需要搜索价值并处理不断增长的字符串池。这可能比处理(和释放)字符串需要更长的时间。尤其是当 JVM 可以通过分代分配和转义分析来优化字符串分配时。

顺便说一句:Java 8u20 有一个功能 ( -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics),可以在 G1 中进行垃圾收集时在后台检测重复的字符串。它将组合这些字符串数组以减少内存消耗。( JEP192 )

于 2014-08-10T01:29:18.757 回答