不可变对象如何帮助减少垃圾回收带来的开销?

2022-09-01 15:36:26

我是一个新手,我已经从这里的前两个答案中阅读了有关垃圾收集的信息

现在,与使用现有对象(在多线程应用程序中)相比,即使程序员必须创建新对象,也要证明使用不可变对象是合理的,本教程说,由于垃圾回收而导致的内存开销的减少,以及消除代码以保护可变对象免受线程干扰和内存一致性错误,可以弥补对象创建的成本:

对象创建的影响经常被高估,并且可能被与不可变对象相关的一些效率所抵消。其中包括由于垃圾回收而减少的开销,以及消除保护可变对象免受损坏所需的代码。

问题是如何实现?垃圾回收与对象的可变性或不可变性有什么关系?


答案 1

有时,当对象不可变时,分配较少。

简单示例

 Date getDate(){
   return copy(this.date);
 }

每次共享它时,我都必须复制它,因为它是可变的,否则调用方将能够改变它。如果被叫了很多,分配率将急剧增加,这将给DategetDateGC

另一方面,Java-8日期是不可变的。

LocalDate getDate(){
  return this.date;
}

请注意,由于不可变性,我不需要复制日期(分配新对象)(我很高兴与您共享该对象,因为我知道您无法更改它)。

现在你可能会想,我怎么能把它应用到“有用”或复杂的数据结构中,而不会造成大量的分配(由于防御性副本),你是绝对正确的,但是有一种艺术叫做和(即:你得到的错觉是它是一个新的副本,实际上副本与原始副本共享很多)。functional programmingpersistent data structures

人们不应该感到惊讶的是,大多数函数式语言(我所知道的所有函数式语言)都是垃圾收集的。


答案 2

不可变对象不需要防御性副本,如果您跨上下文共享它们(例如调用您不信任的代码)或线程安全。这可能意味着不可变对象的读取量在垃圾方面可能会降低。

另一方面,每次更改不可变对象时,无论是否需要创建新对象,都必须创建新对象。在这方面,不可变对象可以创建更多的垃圾。

真正的问题是你是进行大量读取,还是大量写入(或混合),根据用途,不可变对象可以保存对象或创建更多对象,因此根据您的特定用例使用不可变对象或可变对象是有意义的。

注意:大多数时候,正确性远比性能重要得多,虽然恕我直言,一般来说,不可变对象具有更高的开销,但使用不可变对象证明数据模型的正确性要容易得多,并且值得使用不可变对象来简化推理。