深入java字符串常量池

深入java字符串常量池

String对象在java语言中是最常用的类,本文我们将详解字符串池——jvm存储字符串的特定内存区域。

字符串驻留

因为java中字符串是不可变对象,jvm在字符串池中仅保存一份字符串常量,用于优化内存分配。这个过程称为驻留(interning)。

通过直接赋值方式创建字符串变量,jvm在字符串池搜索相应的值。如果找到,java编译器简单返回该内存地址引用,无需额外分配内存。没找到,字符串值被增加至字符串池中驻留,并返回其引用。下面通过代码测试并验证:

String constantString1 = "Baeldung";
String constantString2 = "Baeldung";

assertThat(constantString1)
  .isSameAs(constantString2);

使用构造函数创建字符串变量

当我们通过new 操作符场景字符串变量,java编译器会在堆中创建一个新对象,这种方式创建的变量会指向各自的内存区域。让我们测试两者的区别:

String constantString = "Baeldung";
String newString = new String("Baeldung");

assertThat(constantString).isNotSameAs(newString);

手动驻留

可以通过调用intern()方法手动驻留字符串至字符串池中。手动驻留字符串会使其保存在池中并返回其引用。通过示例进行验证:

String constantString = "interned Baeldung";
String newString = new String("interned Baeldung");

assertThat(constantString).isNotSameAs(newString);

String internedString = newString.intern();

assertThat(constantString)
  .isSameAs(internedString);

垃圾收集

java7之前,JVM在永久代(PermGen space)中方字符串池,其大小固定,不能在运行时扩展,没有资格进行垃圾回收。
在PermGen(而不是堆)中保存字符串有一定风险,如果我们在JVM中保存太多的字符串,JVM可能会抛OutOfMemory错误。

从java7之后,java字符串池存储在堆中(Heap space),可以被垃圾回收。所以未引用字符串会被回收并释放内存,减少OutOfMemory错误。

java9 说明

在Java 8之前,字符串内部被表示为字符数组——char[],用UTF-16编码,所以每个字符占两个字节空间。
Java 9提供了一种新的表示,称为紧凑字符串。这种新格式将根据存储的内容在char[]和byte[]之间选择适当的编码。
由于新的字符串表示只在必要时使用UTF-16编码,因此堆内存的数量将显著降低,从而减少JVM上的垃圾收集器开销。

总结

本文我们介绍了java 中字符串存储情况,以及如何利用字符串池进行内存优化。

你可能感兴趣的:(java8~9核心功能)