0

With the arrival of Java 8 we got lambda and streams, and we all start doing "functional programming". One of the properties of functional programing is immutability. To create immutable object in java is not so easy, but it is possible.

Here is the simple example:

public class Test {

    public static void main(String []args){

       PersonService personService = new PersonService(); 
       
       Person p = Person.of("XYZ", 12);
       Person p2 = personService.setName(p, "New Name");
       Person p3 = personService.setAge(p2, 45);
       
       System.out.println(p);
       System.out.println(p2);
       System.out.println(p3);
    }
}

class PersonService {
   
   public Person setName(Person existingPerson, String name) {
       return Person.of(name, existingPerson.getAge());
   }
   
   public Person setAge(Person existingPerson, int age) {
       return Person.of(existingPerson.getName(), age);
   }
}

final class Person {
   private final String name;
   private final int age; 
   
   private Person(String name, int age) {
       this.name = name;
       this.age = age;
   }
   
   public String getName() {
       return this.name;
   }
   
   public int getAge() {
       return this.age;
   }
   
   public static Person of(String name, int age) {
       return new Person(name, age);
   }
   
   public String toString() {
       return name + " " + age;
   }
}

Many people think garbage collection collects and discards dead objects. In reality, Java garbage collection is doing the opposite! Live objects are tracked and everything else designated garbage. Also Java garbage collection is based on assumption that most objects die young (not referenced anymore shortly after their creation and as such can be destroyed safely). Most developers used to believe that objects creation in Java is slow and that creation of the new objects should be avoided as much as possible. In fact, it does is quite cheap and fast. What is expensive though is an unnecessary creation of long-lived objects which eventually may fill up heap and cause problems.

So is using immutable objects better for GC, because they are not going to live very long ?

  • Creating an immutable object is relatively easy. For simple objects you just need to omit setters (for private properties obviously). The constructor doesn't need to be private. It only gets complicated if the object references other objects. They need to be immutable too, or you need to make defensive copies such as if a mutable `StringBuilder` were passed in. – Kayaman Nov 03 '20 at 20:35
  • Does this answer your question? [How do Immutable Objects help decrease overhead due to Garbage Collection?](https://stackoverflow.com/questions/35384393/how-do-immutable-objects-help-decrease-overhead-due-to-garbage-collection) – Savior Nov 03 '20 at 20:38
  • One of the problems with "So is using immutable objects better for GC," is "better" isn't objective. Some patterns will be better in terms of allowing objects to become eligible for GC sooner. Some patterns will be better in terms of reusing objects and not allowing them to need GC. Some patterns will be better based on tunings of eden space. Etc. – Jeff Scott Brown Nov 03 '20 at 20:49

1 Answers1

1

So is using immutable objects better for GC, because they are not going to live very long ?

This is not answerable. You speak as if there is only one GC but that's not how it works: There are many GC implementations available, and on bootup you pick the one you want to use. Most of the implementations available are also extensively configurable.

For example, the new zgc has the aim of not interrupting running code (collecting occurs as your VM just keeps running; few 'GC pauses', and when they occur, they don't last long, but in tradeoff ZGC generally takes more CPU cycles over the lifetime of the VM than other GCs, which is why you can choose which GC you want. There is no one set answer that is superior for all foreseeable workloads). Currently (source: Inside Java podcast episode on ZGC) it does not do much in the way of generational systems, which means creating a ton of garbage is probably slower with ZGC than having mutable objects.

As you say, a lot of GCs will use generational technology and thus can handle boatloads of short-lived garbage well - theoretically, collecting a lot of short-lived garbage is faster than a few long-lived garbage objects with such GCs.

Is it 'faster' to have a lot of short lived garbage? Nah.

Is it 'slower'? Nah.

The point is to think big: We (us humans) know how to adapt garbage collectors so that they can handle tons of short lived garbage efficiently. Combine that with the fact that java as a language is clearly moving to (and therefore, the engineers working on said GCs are aware of) a world where a ton of real life apps will have a lot of short lived garbage.

That means that if it is a problem, it will be addressed.

Therefore, you should program so that your code is 'clean'. Which is a weasel word, so I will define it: Easy to maintain, easy to read, easy to test, easy to change in the face of changing requirements, easily connected to other systems and adapted for other uses.

And if in so writing code you end up making a ton of short lived garbage? Doesn't matter. Don't get 'pre-swayed' to change how your code works based off of either a single report on how some specific GC impl is designed, nor by nebulous drivel that ascribes to generational collectors some sort of mythical ability to be magically faster than alternatives either.

If you have a real life scenario where your JVM is too slow or otherwise problematic, get a report, and if that report says a ton of short lived objects are really the problem then tweak GC settings. If that doesn't help, guess what? Time to change the code, you gotta deploy right now, you can't wait around for nebulous dreams to come true. The crucial lesson here is not to try to predict that you end up here and write code accordingly, because we are mere mortals and that is some godlike power beyond humanity. No: The lesson is, write your code 'clean' (as defined above), because clean code is easily adapted in the face of specific performance needs. This in sharp contrast to writing code when your concern is anything but clean code (such as: Concerned about either making few objects or making a ton of short lived ones, instead of well designed code) - because then a need to change things is going to be complicated.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72