方法本地字符串内存分配?

时间:2014-08-08 17:24:38

标签: java string string-pool

我理解String pool和intern()方法在java中是如何工作的。这是一个简短的介绍。

Java 6中的String.intern()

  

在那些美好的旧时代,所有实习字符串都存储在PermGen中    - 堆的固定大小部分主要用于存储加载的类   和字符串池。除了明确的实习字符串,PermGen字符串   pool还包含程序中先前使用的所有文字字符串   (这里使用的重要词 - 如果一个类或方法永远不会   加载/调用,其中定义的任何常量都不会被加载。

     

Java 6中这种字符串池的最大问题是它的位置 -   PermGen。 PermGen具有固定的大小,无法扩展   运行。您可以使用-XX:MaxPermSize = 96m选项进行设置。就我而言   知道,默认的PermGen大小在32M到96M之间变化,具体取决于   该平台。你可以增加它的大小,但它的大小仍然是   固定。这种限制需要非常小心地使用String.intern -   你最好不要使用这种方法实习任何不受控制的用户输入。   这就是为什么Java 6时代的字符串池主要实现的原因   手动管理的地图。

Java 7中

String.intern()

  

Oracle工程师对字符串进行了非常重要的更改   Java 7中的池化逻辑 - 字符串池被重定位到堆中。   这意味着您不再受限于单独的固定尺寸   记忆区。所有字符串现在都位于堆中,与其他大多数字符串一样   普通对象,它允许您只管理堆大小   调整你的申请。从技术上讲,仅此一点就足够了   有理由重新考虑在Java 7程序中使用String.intern()。   但还有其他原因。

Source

确定到目前为止我对字符串存储在内存中的方式感到满意,直到我遇到此工具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);
   }


}

我得到了以下结果:

Visualizer Output

正如您所看到的,字符串文字和具有相同值的对象会重复并存储在堆栈中,并且堆空间不会出现在方法本地字符串的图片中。 我一开始很困惑但后来我搜索并发现了逃逸分析这是由JDK 7自动完成的。但是在我的代码中,我创建了一个String对象,它应该存储在堆上但是它在堆栈中,你可以在visualizer输出中看到,但是我的Dummy类对象存储在堆上。我无法真正掌握这种行为。 方法本地字符串与其他对象和实例级别字符串的处理方式有何不同?

1 个答案:

答案 0 :(得分:1)

我认为你误解了可视化器输出。堆栈中有三个引用到字符串对象,对应lonelyMethod中的三个局部变量。似乎“为了您的方便”,Java Visualizer显示引用对象的字符串表示形式,但这不是堆栈中的实际内容。引用的对象看起来都相同,但其中两个引用了实际的字符串“悬空”,第三个(实际上是第二个,对应于变量test)引用了堆上的单独String对象。

我认为Java Visualizer可能已经为堆栈上的每个对象引用显示了标识哈希码,但这(通常)不那么有用。也许可视化器中有一个设置可以启用此类行为。这将有助于澄清正在发生的事情。