当调用string intern()方法时

时间:2013-09-24 22:33:37

标签: java string memory-management

  

案例1:

  String str = "StackOverFlow";
  String str1 = "StackOverFlow";
  if(str==str1){
      System.out.println("equal");//prints equal
  }
     

案例2:

  String str = "StackOverFlow";
  String str1=str.intern();
  if(str==str1){
      System.out.println("equal");//prints equal
  }

跟进问题:

  1. 我想知道第一种情况是JVM在内部调用intern()并将str的引用分配给str1

  2. 第一种情况下两个引用如何相等?

  3. 第一种情况是否意味着无论何时声明像String str = "StackOverFlow";这样的字符串,它都会添加到字符串池中,与intern()方法相同?

  4. String str = "StackOverFlow";intern()使用的字符串池是否在堆外分配?如果确实在哪里?


  5. 对于问题4,答案如下:

    在Java 6及更早版本中,实习字符串也存储在永久代中。在Java 7中,实习字符串存储在主对象堆中。

    以下是文档说明的内容:

      

    在JDK 7中,永久性中不再分配实习字符串   生成Java堆,而是在main中分配   Java堆的一部分(称为年轻和老一代)   与应用程序创建的其他对象。这种改变会   导致更多数据驻留在主Java堆中,并且数据中的数据更少   永久世代,因此可能需要堆大小   调整。大多数应用程序只会看到相对较小的差异   由于此更改导致堆使用,但加载的应用程序更大   许多课程或大量使用String.intern()方法都会看到   更显着的差异。

    此处的详细信息:

    Java 6中的String.intern()

      

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

    The biggest issue with such string pool in Java 6 was its location – the PermGen. PermGen has a fixed size and can not be expanded at
    
         

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

    Java 7中

    String.intern()

      

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

4 个答案:

答案 0 :(得分:5)

引用是相同的,因为它们都是字符串文字。

intern() str不需要intern(),因为它也是文字。当你需要使用equals()(顺便说一下比final String str1 = "I am a literal"; final String str2 = new String(str1.toCharArray()); final boolean check1 = str1 == str2; // false final boolean check2 = str1 == str2.intern(); // true 慢得多,所以不要使用它)时,你需要使用一个例子来构造一个带有byte或char数组的String

例如:

{{1}}

答案 1 :(得分:2)

  

1)我想知道对于第一种情况,JVM是否在内部调用intern()并将str的引用分配给str1?

嗯,是的,没有。

是内部调用intern()方法 。但是,当运行该代码时,调用不会发生。实际上,当代码加载时会发生这种情况。然后,加载程序将引用保存到实习字符串。

但在这种情况下,加载过程只需要进行一次实习。这两个文字(在这种情况下)实际上将由正在加载的类中的单个“常量池条目”表示。 (Java编译器将在编译时发现类中的重复文字...并将其删除。)

  

2)第一种情况下两个引用如何相等?

因为这两个字符串已被实习。

  

3)第一种情况是否意味着每当你声明一个像String str =“StackOverFlow”这样的字符串时;它添加到字符串池中与intern()方法相同?

是...模数在运行包含声明的代码时不会发生实习。

  

4)String str = "StackOverFlow";intern()使用的字符串池是否在堆外分配?如果确实在哪里?

答案在某种程度上取决于系统。通常,字符串池在堆中。在某些系统上,堆被分成具有不同垃圾收集策略的区域或空间,并且字符串池在所谓的“permgen”空间中分配,该空间的大小独立于堆的其余部分。但这并非总是如此。

答案 2 :(得分:1)

  

我想知道对于第一种情况,JVM是否在内部调用intern()

没有

  

并将str的引用分配给str1?

是的,但是因为价值是文字,而不是因为实习。首先,.class文件中只有一个实例。

  

第一种情况下两个引用如何相等?

这不是另一个问题,只是同样的问题重申了。

  

第一种情况是否意味着每当你声明一个像String str =“StackOverFlow”这样的字符串时;它添加到字符串池中与intern()方法相同?

是的,但它是由编译器完成的,而不是intern()。

  

String str使用的字符串池是否为“StackOverFlow”;和intern()是在堆外部分配的吗?

没有

  

到底在哪里?

在加载类的常量池中,它位于堆中。

答案 3 :(得分:0)

有两种创建字符串对象的方法。

一个是

String str = "test-String"; // This string is created in string pool or returned from
string pool if already exists

第二个

String str = new String("test-string");// This string object will be created in heap memory and will be treated as any other object

当您使用new运算符创建的字符串实例上调用string.intern时...此字符串将在字符串池中创建或从池中返回(如果存在)。这是一种将字符串对象从堆移动到perm Gen(字符串池)

的机制