java - 不可变对象(immutable对象)的内存管理

标签 java memory-management immutability

我对java等语言中String对象等Immutable对象的内存管理有一个概念上的疑惑。例如,如果我有一个包含值“Hello”的字符串对象“str”,我将执行以下操作:

String str = "Hello";
str = str.concatenate("World");

在这种情况下,据我所知,将创建一个状态为“Hello World”的新字符串对象并将其引用回 str。现在,在 Java 中(以及大多数其他面向对象的语言中)任何对象的生命周期只要它的引用是活着的。那么持有“Hello”的对象到哪里去了。它是否驻留在内存堆中直到垃圾收集器自行处理它?另外,那些不支持垃圾收集器而必须依赖类析构函数的语言呢?

此外,如果像 StringBufferStringBuilder 这样的可变对象更加灵活且性能友好,为什么在设计语言时首先要使对象不可变? (我的意思是为什么字符串对象不是从一开始就可变的,而不必在后续的 JDK 版本中引入新的结构,例如字符串缓冲区?)。

如果有人可以指导我,那就太好了。我对此很陌生,因此非常感谢您提供清晰,基本的解释。谢谢。

最佳答案

这实际上是一个特别关于 java String 类的问题——不是一般的不变性。首次引入 Java 时,设计者决定使 String 变得特殊——在某些方面,它介于引用类型和原始类型之间。

我们使用 String 获得的优势是虚拟机保留了一个通用的字符串文字池,以阻止堆被填满 - 参见 here以获得描述。这背后的原因是程序的大部分内存都可以用来存储常用的字符串。另见 String.intern .

对于任何其他类型的不可变对象(immutable对象),情况并非如此(遗憾的是)。您关于 str 去向的问题已由其他人回答 - 它遵循正常的垃圾收集规则,我相信您知道(或可以找到)。

也许您问题中最有趣的部分是

Also, if mutable objects such as StringBuffer/StringBuilder are much more flexible and performance friendly, why make objects mutable in the first place, while designing the language?? (I mean why aren't String Objects mutable right from the beginning instead of having to introduce new structures such as String Buffers in subsequent jdk releases?).

我的回答是,常见情况是我们有很多相同的字符串,我们希望针对常见情况进行优化。另请注意,Java 编译器在连接字符串时使用 StringBuilder。例如拿这段代码

public class StringBuilderTest {

  public static void main(String [] args){

    String hello = "hello ";
    String world = "world";
    System.out.println(hello+world);
   }
}

并使用

反汇编它

javap -c StringBuilderTest

并为 main 方法获取以下字节码

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String hello 
       2: astore_1      
       3: ldc           #3                  // String world
       5: astore_2      
       6: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       9: new           #5                  // class java/lang/StringBuilder
      12: dup           
      13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      16: aload_1       
      17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      20: aload_2       
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      27: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      30: return        
}

它使用 StringBuilder 来执行追加。

关于java - 不可变对象(immutable对象)的内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16957203/

相关文章:

c - 如何释放返回的 malloced 字符串?

javascript - 从嵌套对象中删除数据而不改变

java - 如何在 Java 中创建不可变对象(immutable对象)?

java - 支柱 : Generating HTML instead of a simple message?

java - Android服务尚未绑定(bind)

java - 如何在java中读取docker-compose.yml文件

python - Python 函数调用后是否仍然使用内存?

c - 有没有办法查询 realloc 会做什么,或者阻止它复制 Windows 和 Linux 上的所有内存?

java - Collections.shuffle 只工作一次

build - 在主机上挂载Docker卷,但将文件设置为 “immutable”吗?