28

I am a newb, and I have read about Garbage Collection from the first two answers here.

Now justifying the use of Immutable Objects even if the programmer has to create new objects, as compared to using existing objects (in multi-threaded applications), this tutorial says that the cost of object creation is made up for by the decrease in memory overhead due to garbage collection, and the elimination of code to protect mutable objects from threads interference and memory consistency errors:

The impact of object creation is often overestimated, and can be offset by some of the efficiencies associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.

The question is how? What does Garbage Collection have to do with Mutability or Immutability of objects?

Community
  • 1
  • 1
Solace
  • 8,612
  • 22
  • 95
  • 183
  • 4
    Modern GC is extremely efficient with objects that "die young". Don't be afraid of creating and using objects with short lifespan; but do be careful with keeping referencing objects for longer time (e.g. for caching). The issue is not actually about immutability, more about lifespan. – ZhongYu Feb 13 '16 at 20:10
  • 3
    In the tutorial you linked, the exact phrase is _"decreased overhead due to garbage collection"_. There is no word "memory" in it. You should correct it in your question, because immutable objects may actually consume more memory (because you are forced to create a new one if you want something changed in the existing one), while decreasing the overall burden on GC nevertheless. More details in my answer below. – Dragan Bozanovic Feb 13 '16 at 23:04

3 Answers3

21

Sometimes you allocate less when objects are immutable.

Simple example

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

I have to copy Date every time I share it because it is mutable or the caller would be able to mutate it. If getDate get called a lot,the allocation rate will dramatically increase and this would put pressure on the GC

On the other hand, Java-8 dates are immutable

LocalDate getDate(){
  return this.date;
}

Notice that I don't need to copy date (allocate a new object) because of immutability ( I am happy to share the object with you because I know that you can't mutate it).

Now you might think how can I apply this to "useful" or complicated data structures without causing massive allocation (due to defensive copies), you are absolutely right, but there is an art called functional programming and persistent data structures ( ie: you get the illusion that it's a new copy where in fact copies share a lot from the original).

One shouldn't be surprised that most functional languages (all the ones that I am aware of) are garbage collected.

Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
  • Thank you very much. While the answer other than the last two paragraphs made it clear for me, I couldn't make much sense of the last two paragraphs. You can throw some light there if you have time, otherwise it's fine. Thank you again for the answer. – Solace Feb 13 '16 at 21:22
  • @Solace are you aware of functional data structures? they do a lot of tricks to avoid "naive" defensive copies. – Sleiman Jneidi Feb 13 '16 at 22:13
  • 4
    @Solace One (very simple, classical) example is a list: When you have a lists that is immutable, e.g. a list `[a,b,c,d,e]`, then you can implement this (immutable!) data structure in a way that allows you to ""remove"" the first two elements from this list - but this will **not** create a new list or really modify the existing one. Instead, you will obtain the "sublist" `[c,d,e]` that is backed by the same memory as the first one. Also see https://en.wikipedia.org/wiki/Persistent_data_structure and related stackoverflow questions. – Marco13 Feb 14 '16 at 13:17
  • `return copy(this.date);` is the API code, I don't see it anywhere. – hagrawal7777 Feb 17 '18 at 17:57
16

Immutable objects do not need a defensive copy if you are sharing them across contexts (.e.g calling code you don't trust) or for thread safety. This can mean that reads of immutable objects can be lower in terms of garbage.

On the other hand, every time you change an immutable object, you have to create new objects whether this is required or not. In this regard, immutable objects can create far more garbage.

The real question is whether you are making lots of reads, or lots of writes (or a mix) Depending on usage Immutable objects can save objects or create more objects, so it makes sense to use either Immutable or Mutable object based on your specific use case.

Note: most of the time, correctness is far, far more important than performance, and while in general Immutable objects have higher overhead IMHO, it is far easier to prove the correctness of data models using Immutable objects, and it is worth using immutable objects for clarity and ease of reasoning alone.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 3
    I had to mark the other answer as accepted because of that example, but I am grateful for the advice. It is valuable for me. Thank you so very much indeed. – Solace Feb 13 '16 at 21:25
12

In this article Brian Goetz explains it nicely. Basically, it is related with the way garbage collector works. It has less work to do if new objects reference the old ones than vice versa.

Excerpt from the linked article with example classes below:

public class MutableHolder {
  private Object value;
  public Object getValue() { return value; }
  public void setValue(Object o) { value = o; }
}

public class ImmutableHolder {
  private final Object value;
  public ImmutableHolder(Object o) { value = o; }
  public Object getValue() { return value; }
}

In most cases, when a holder object is updated to reference a different object, the new referent is a young object. If we update a MutableHolder by calling setValue(), we have created a situation where an older object references a younger one. On the other hand, by creating a new ImmutableHolder object instead, a younger object is referencing an older one.

The latter situation, where most objects point to older objects, is much more gentle on a generational garbage collector. If a MutableHolder that lives in the old generation is mutated, all the objects on the card that contain the MutableHolder must be scanned for old-to-young references at the next minor collection.

The use of mutable references for long-lived container objects increases the work done to track old-to-young references at collection time.

Escape analysis

Regarding the concern that lots of objects are created because you instantiate a new object whenever you need to change the existing one, the object allocation mechanism is much improved in latest JVMs.

Take a look at escape analysis (also mentioned in the linked article). Many object will not be allocated on heap (but be inlined/allocated on stack), so GC will have nothing to do with them (actually GC is not aware that those objects exist at all).

Although not related only to immutability, escape analysis mechanism can be utilised more efficiently in an immutable context (an example is the Person object which is not changed during the method invocation in the linked Oracle docs).

joe_specimen
  • 295
  • 3
  • 19
Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • 1
    Although it's not *strictly* related to immutability, the keyword **"escape analysis"** is indeed worth pointing out in this context (I would have created an own answer for that, but it is also explained in the article that you linked to). +1 – Marco13 Feb 14 '16 at 13:12
  • I think this is the main reason why immutability and garbage collection make a good fit. Especially if you imagine some call frame, arena based system, where upon exit of a call frame, garbage collection is triggered. Older objects (created in a prior call frame) can never reference new objects created in this call frame, if all is immutable. – BitTickler Nov 02 '20 at 13:13
  • "If a MutableHolder that lives in the old generation is mutated, all the objects on the card that contain the MutableHolder must be scanned for old-to-young references at the next minor collection. " Could you give a little more details on this? – seal Apr 23 '22 at 09:55