当调用string intern()方法时

Try*_*ing 2 java string memory-management

情况1:

  String str = "StackOverFlow";
  String str1 = "StackOverFlow";
  if(str==str1){
      System.out.println("equal");//prints equal
  }
Run Code Online (Sandbox Code Playgroud)

案例2:

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

跟进问题:

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

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

  3. 第一种情况是否意味着每当你声明一个字符串时String str = "StackOverFlow";它会像方法那样添加到字符串池中intern()

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


对于问题4,答案如下:

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

这是文档说的:

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

更多细节来自:

Java 6中的String.intern()

在那些美好的旧时代,所有实习字符串都存储在PermGen中 - 堆的固定大小部分主要用于存储加载的类和字符串池.除了显式内部字符串之外,PermGen字符串池还包含程序中较早使用的所有文字字符串(此处使用的重要字 - 如果从未加载/调用类或方法,则不会加载其中定义的任何常量).

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
Run Code Online (Sandbox Code Playgroud)

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

Java 7中的String.intern()

Oracle工程师对Java 7中的字符串池逻辑进行了非常重要的更改 - 字符串池已重新定位到堆中.这意味着您不再受限于单独的固定大小的内存区域.所有字符串现在都位于堆中,与大多数其他普通对象一样,它允许您在调整应用程序时仅管理堆大小.从技术上讲,仅此一点可能是重新考虑在Java 7程序中使用String.intern()的充分理由.但还有其他原因.

Obi*_*ere 5

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

intern()呼叫str没有必要的,因为它也是一个文字.在构造带有byte或char数组的String 时,你需要使用的一个例子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
Run Code Online (Sandbox Code Playgroud)