我理解String pool和intern()方法在java中是如何工作的。这是一个简短的介绍。
Java 6中的String.intern()
Java 7中在那些美好的旧时代,所有实习字符串都存储在PermGen中 - 堆的固定大小部分主要用于存储加载的类 和字符串池。除了明确的实习字符串,PermGen字符串 pool还包含程序中先前使用的所有文字字符串 (这里使用的重要词 - 如果一个类或方法永远不会 加载/调用,其中定义的任何常量都不会被加载。
Java 6中这种字符串池的最大问题是它的位置 - PermGen。 PermGen具有固定的大小,无法扩展 运行。您可以使用-XX:MaxPermSize = 96m选项进行设置。就我而言 知道,默认的PermGen大小在32M到96M之间变化,具体取决于 该平台。你可以增加它的大小,但它的大小仍然是 固定。这种限制需要非常小心地使用String.intern - 你最好不要使用这种方法实习任何不受控制的用户输入。 这就是为什么Java 6时代的字符串池主要实现的原因 手动管理的地图。
String.intern()
Oracle工程师对字符串进行了非常重要的更改 Java 7中的池化逻辑 - 字符串池被重定位到堆中。 这意味着您不再受限于单独的固定尺寸 记忆区。所有字符串现在都位于堆中,与其他大多数字符串一样 普通对象,它允许您只管理堆大小 调整你的申请。从技术上讲,仅此一点就足够了 有理由重新考虑在Java 7程序中使用String.intern()。 但还有其他原因。
确定到目前为止我对字符串存储在内存中的方式感到满意,直到我遇到此工具Java Visualizer。我写了一些简单的Java类来可视化如何在程序中分配内存。
public class A {
String iWillAlwaysBeOnHeap="I am on heap...!!!";
class Dummy{
private int dummyNumber;
Dummy(int dummyNumber)
{
this.dummyNumber=dummyNumber;
}
}
public static void main(String[] args) {
A a=new A();
a.lonelyMethod();
}
public void lonelyMethod()
{
String lostString="dangling";
String test=new String("dangling");
test.intern();
String duplicateLiteral="dangling";
Dummy dummy=new Dummy(4);
}
}
我得到了以下结果:
正如您所看到的,字符串文字和具有相同值的对象会重复并存储在堆栈中,并且堆空间不会出现在方法本地字符串的图片中。 我一开始很困惑但后来我搜索并发现了逃逸分析这是由JDK 7自动完成的。但是在我的代码中,我创建了一个String对象,它应该存储在堆上但是它在堆栈中,你可以在visualizer输出中看到,但是我的Dummy类对象存储在堆上。我无法真正掌握这种行为。 方法本地字符串与其他对象和实例级别字符串的处理方式有何不同?
答案 0 :(得分:1)
我认为你误解了可视化器输出。堆栈中有三个引用到字符串对象,对应lonelyMethod
中的三个局部变量。似乎“为了您的方便”,Java Visualizer显示引用对象的字符串表示形式,但这不是堆栈中的实际内容。引用的对象看起来都相同,但其中两个引用了实际的字符串“悬空”,第三个(实际上是第二个,对应于变量test
)引用了堆上的单独String
对象。
我认为Java Visualizer可能已经为堆栈上的每个对象引用显示了标识哈希码,但这(通常)不那么有用。也许可视化器中有一个设置可以启用此类行为。这将有助于澄清正在发生的事情。