CodeGym /Java Blog /Java Objects /Object lifecycle
Author
John Selawsky
Senior Java Developer and Tutor at LearningTree

Object lifecycle

Published in the Java Objects group
Hi! I think you wouldn't be very surprised if I told you that your computer has a limited amount of memory :)
Object lifecycle  - 1
Even your hard drive (which is many, many times the size of RAM) can get chock full of your favorite games, TV shows, and other things. To prevent this from happening, you need to monitor the current state of your computer's memory and delete unnecessary files. How does all this relate to Java programming? Quite directly! After all, creating any object causes the Java machine to allocate memory for it. A large real-world program creates tens or hundreds of thousands of objects, and a chunk of memory is allocated for each of them. But what do you think, how many of these objects exist? Are they "alive" all the while our program is running? Of course not. Even with all their advantages, Java objects are not immortal :) Objects have their own lifecycle. Today we'll take a little break from writing code and explore this process :) It's also very important for understanding how a program works and for managing resources. So, where does an object's life begin? Like a human, from birth, i.e. when it is created.

Cat cat = new Cat();// Our Cat object's lifecycle begins now!
First, the Java virtual machine allocates the memory necessary to create the object. Then it creates a reference to it (in our case, cat) to make it possible to keep track of it. Then all the variables are initialized, the constructor is called, and our fresh object is now living its own life :) Object lifetimes vary. There are no exact figures here. In any event, an object lives in the program and performs its functions for some period of time. To be precise, the object is "alive" as long as there are references to it. As soon as there are no references, the object "dies". For example:

public class Car {
  
   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");
       lamborghini = null;

   }

}
In the main() method, the "Lamborghini Diablo" Car object ceases to be alive on the second line. There was only one reference to it, and the reference was set to null. Since there are no remaining references to the Diablo, it becomes "garbage". A reference doesn't have to be set to zero for this to happen:

public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");

       Car lamborghiniGallardo = new Car("Lamborghini Gallardo");
       lamborghini = lamborghiniGallardo;
   }

}
Here we've created a second object and assign it to the lamborghini reference. Now two references point to the Lamborghini Gallardo object, but the Lamborghini Diablo object has none. This means the Diablo object becomes garbage. This is when Java's built-in garbage collector (GC) kicks in.
Object lifecycle  - 2
The garbage collector is an internal Java mechanism responsible for freeing up memory, i.e. removing unnecessary objects from memory. There's a reason why we chose to represent it with a robot vacuum cleaner. The garbage collector works in about the same way: it "moves about" your program in the background, collecting garbage. You practically don't have to interact with it. Its job is to delete objects that are no longer used in the program. Thus, it frees up memory for other objects. Do you remember that at the beginning of the lesson we said in real life you have to monitor your computer's state and delete old files? If we're talking about Java objects, the garbage collector does this for you. The garbage collector is started many times as your program runs: you don't have to explicitly call it and give it commands (though this is technically possible). We'll talk more about the garbage collector later and analyze how it works in more detail. When the garbage collector reaches an object—just before it is destroyed—the object's special finalize() method is called. This method can be invoked to release certain additional resources used by the object. The finalize() method belongs to the Object class. In other words, it's similar to equals(), hashCode() and toString() (which you've previously met). Every object has it. It differs from other methods in that...how should we say this...it's very willful. By that we mean that it is not always called before an object is destroyed. Programming is a very precise activity. The programmer tells the computer to do something, and the computer does it. I assume you've become accustomed to this sort of behavior, so at first it may be difficult for you to accept the following idea: "Before an object is destroyed, the Object class's finalize() method is called. Or not. If we get lucky!" Still, this is reality. The Java machine itself determines whether to call finalize() on a case by case basis. As an experiment, let's try running the following code:

public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public Cat() {
   }

   public static void main(String[] args) throws Throwable {

       for (int i = 0 ; i < 1000000; i++) {

           Cat cat = new Cat();
           cat = null;// The first object becomes available for garbage collection here
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("The Cat is destroyed!");
   }
}
We create a Cat object, and in the next line we zero out the only reference to it. And we do that a million times. We've explicitly overridden the finalize() method. Each time a Cat object is destroyed, it must display a string—a total of one million times. But no! To be exact, on my computer it was executed only 37346 times! In other words, my Java machine decided to call the finalize() method in only 1 out of every 27 cases. In the other cases, garbage collection didn't involve this call. Try running this code yourself. You will most likely get a different result. As you can see, it's hard to call finalize() a reliable partner :) So, here's a small tip for the future: don't rely on the finalize() method to release critical resources. The JVM might call it, or it might not. Who knows? If your object held some performance-critical resources (for example, an open database connection) while it was alive, it would be better to create and explicitly call a special method to release them when the object is no longer needed. That way, you'll know for sure that your program's performance won't suffer. We started by saying that working with memory and garbage collection are very important topics, and indeed they are. Mishandling resources and misunderstanding how unnecessary objects are cleaned up can lead to one of the most unpleasant bugs: memory leaks. This is one of the most well-known programming errors. It even has its own Wikipedia article. Poorly written code can create a situation where memory is allocated every time for newly created objects, but old, unnecessary objects are unavailable for garbage collection. Since we've already made robot vacuum cleaner analogy, imagine what would happen if before running the robot you scattered socks all over the house, smashed a glass vase, and left Lego pieces all over the floor. Naturally, the robot would try to do something, but one day it will seize up.
Object lifecycle  - 3
For the vacuum cleaner to run properly, you need to keep the floor in decent shape and pick up everything that it can't handle. The garbage collector follows the same principle. If a program has a lot of objects that it can't clean up (like a sock or Lego for our robotic vacuum cleaner), one day we'll run out of memory. Not only will your program hang, all the other programs that happen to be running on the computer will too. After all, they won't have enough memory either (returning to our analogy, the broken glass on the floor stops not only the vacuum cleaner, but also the people who live in the home). In short, this is what object lifecycle and garbage collection look like in Java. You don't need to memorize this: it's enough to simply understand how it works. In the next lesson, we'll return to these processes in more detail. But for now, you can return to solving CodeGym tasks :) Good luck!
Comments (42)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
NeoBTK Level 8, Katowice, Poland
23 September 2022
finalize() is now deprecated. I don't know since when, but at least from Java 11.
Victor Omoha Level 14, United States of America, United States
2 September 2022
Excellent
Lou Level 6, Spain
1 September 2022
Very instructive! Thanks a lot !
叶葳叶 Level 13, 旧金山, 中国
31 July 2022
我只有247行
null Level 12
10 February 2022
是不是可以理解为只有当内存必须要被清除的时候垃圾回收器才会启动
0wis Level 6, Paris, France
14 December 2021
Thanks for this article ! If I understand well, the Java Garbage Collector job is to take care of cleaning the memory of the object that the program will not use (or even will not be able to access). It uses the finalize() method that is present with every java object. However, the garbage collector use of finalize() method is quite unreliable so it is better to not rely on it. So I'll take it as a safe net and will try to ensure proper cleaning of the memory in my code.
Sansho Level 19, Bordeaux, France
28 March 2021
2 things: 1) finalize() is now deprecated (but can still work when I'm writing this) 2) I wrote this for know how many instances (="rep") does the garbage collector can accept before to start to work. (spoil: 833 || 834 on my machine at least).

public class Solution {
    private static int nbInstances=0, nbInstDelete=0;
    private static double repsFor = 0; 
    
    public Solution(){
        setNbInstances(nbInstances++);    }


    public void setNbInstances(int instances) {
        nbInstances = instances;
    }
 public static void main(String[] args) throws Throwable {
        repsFinder();
    }

    static void repsCount(){
        for (int i = 0; i < Solution.getRepsFor() ; i++, nbInstances=0) { //In the For loops, you can ask to do more things at the end of each loop, with a coma. There, without this last "argument", the loop is infinite
            Solution solur = new Solution(); //Don't mind the name ;)
            solur=null;

        }
     
        nbInstDeleted= repsFor - nbInstances;
     
        System.out.println("Instances deleted: " + nbInstDeleted );
        
       
    }
    static void repsFinder(){
        while(nbInstDeleted==0) {
            repsCount();

            repsFor++;
            System.out.println("Nothing deleted yet. Number tested augmented for 1. Next amount of instances max tested: " + repsFor);
        }
        System.out.println("The java garbage collector works at the " + repsFor + "th rep");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        nbInstances--;
      }
}
Andy Lee Level 10
25 February 2021
perfect
Sinisa Level 11, Banja Luka, Bosnia and Herzegovina
24 February 2021
Fundamentals of garbage collection on M$ .NET (C#) platform: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
aartilumb Level 17, Philadelphia, United States
8 September 2020
Informative article!