我阅读了很多答案,但没有一个能真正准确地回答我的问题。
如果我有一个在某个端口上运行的 java 服务并且客户端连接到它并调用如下方法:
String data = getServiceData("clientKey");
现在我的问题是,这个键(clientKey)会存储在服务端的字符串文字池中吗?通常,要存储在常量池中的文字是在编译时计算出来的,但是从 JVM 外部传递的字符串或读取文件时可能会发生什么情况?
我阅读了很多答案,但没有一个能真正准确地回答我的问题。
如果我有一个在某个端口上运行的 java 服务并且客户端连接到它并调用如下方法:
String data = getServiceData("clientKey");
现在我的问题是,这个键(clientKey)会存储在服务端的字符串文字池中吗?通常,要存储在常量池中的文字是在编译时计算出来的,但是从 JVM 外部传递的字符串或读取文件时可能会发生什么情况?
字符串对象在您的客户端被序列化和反序列化并保存在堆内存中。如果您希望它存储在您的字符串池内存中,您应该使用intern()方法。
String value;
String data = (value =getServiceData("clientKey"))==null?null:value.intern();
大多数从外部源(尤其是 Java 序列化)读取字符串的方法BufferedReader.getLine()
都不会对字符串进行实习,所以答案是否定的。
但是,如果您使用第三方库,他们可能会这样做:例如,已知有一些 XML/Dom 解析器可以这样做(至少对于元素名称,较少用于值)。对于某些字符串(例如 HTTP 标头名称),还有一些高性能框架(servlet 容器)。
但通常它很少用在好的(!)实现中,因为它不像人们想象的那样可取。不要忘记:在你可以实习之前,它必须作为一个无论如何都需要收集的对象存在,所以从避免垃圾使用的角度来看,intern()
它没有帮助。如果这些字符串存活很长时间(它不在 OLTP 中),它只会减少工作集内存,并且可能会稍微加快相等性检查。但通常这仅在您对同一个字符串对象执行数千个操作时才有帮助。
您可以检查自己的字符串是否已经被实习(你当然不应该在生产代码中这样做,因为它实习你的字符串并且它可能不适用于所有实现):
input == input.intern()?"yes":"no"`
是的(如评论中所问),可能会发生数百万个相同 API 密钥的实例。但不要误以为这是一件坏事。实际上,实习他们需要搜索价值并处理不断增长的字符串池。这可能比处理(和释放)字符串需要更长的时间。尤其是当 JVM 可以通过分代分配和转义分析来优化字符串分配时。
顺便说一句:Java 8u20 有一个功能 ( -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics
),可以在 G1 中进行垃圾收集时在后台检测重复的字符串。它将组合这些字符串数组以减少内存消耗。( JEP192 )