Object Destruction Finalize Method

Introduction

Object destruction in Java is handled automatically by Garbage Collection (GC). The finalize() method was used for cleanup before garbage collection, but it’s deprecated since Java 9.


Garbage Collection

Automatic memory management - Java automatically destroys unused objects.

How it Works:

  1. Object created in heap memory
  2. When no references point to object
  3. Garbage collector marks it for collection
  4. Memory is freed

Example:

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("John");  // Object created
        Student s2 = new Student("Alice"); // Object created

        s1 = null;  // Object "John" eligible for GC
        s2 = null;  // Object "Alice" eligible for GC

        // Request garbage collection (not guaranteed)
        System.gc();
    }
}

class Student {
    String name;

    Student(String name) {
        this.name = name;
    }
}

When Object is Eligible for GC

1. Reference Set to null:

Student s = new Student("John");
s = null;  // Object eligible for GC

2. Reference Reassigned:

Student s = new Student("John");
s = new Student("Alice");  // "John" object eligible for GC

3. Object Created Inside Method:

void method() {
    Student s = new Student("John");
    // After method ends, 's' is eligible for GC
}

4. Island of Isolation:

class Node {
    Node next;
}

Node n1 = new Node();
Node n2 = new Node();
n1.next = n2;
n2.next = n1;

n1 = null;
n2 = null;
// Both objects eligible (isolated)

finalize() Method (Deprecated)

Called by garbage collector before destroying object.

Syntax:

protected void finalize() throws Throwable {
    // Cleanup code
}

Example:

class Student {
    String name;

    Student(String name) {
        this.name = name;
        System.out.println(name + " created");
    }

    // finalize method (deprecated)
    @Override
    protected void finalize() throws Throwable {
        System.out.println(name + " destroyed");
    }
}

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("John");
        Student s2 = new Student("Alice");

        s1 = null;
        s2 = null;

        // Request GC
        System.gc();

        // Give time for GC
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Note: finalize() execution is not guaranteed.


Problems with finalize()

  1. Unpredictable: Don’t know when it will run
  2. Not Guaranteed: May never run
  3. Performance: Slows down GC
  4. Deprecated: Since Java 9
  5. Unreliable: Should not depend on it

Modern Alternatives

1. Try-with-Resources (Preferred):

try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    // Use resource
} // Automatically closed

2. Explicit Cleanup Method:

class Database {
    Connection conn;

    void connect() {
        // Connect to database
    }

    // Explicit cleanup
    void close() {
        if (conn != null) {
            conn.close();
        }
    }
}

// Usage
Database db = new Database();
try {
    db.connect();
    // Use database
} finally {
    db.close();  // Explicit cleanup
}

3. Cleaner API (Java 9+):

import java.lang.ref.Cleaner;

class Resource {
    private static final Cleaner cleaner = Cleaner.create();

    private final Cleaner.Cleanable cleanable;

    Resource() {
        this.cleanable = cleaner.register(this, new CleanupTask());
    }

    private static class CleanupTask implements Runnable {
        @Override
        public void run() {
            // Cleanup code
            System.out.println("Cleanup performed");
        }
    }
}

Requesting Garbage Collection

Methods:

// Method 1
System.gc();

// Method 2
Runtime.getRuntime().gc();

Important: These are requests, not commands. JVM may ignore.

Example:

class Demo {
    int id;

    Demo(int id) {
        this.id = id;
        System.out.println("Object " + id + " created");
    }

    @Override
    protected void finalize() {
        System.out.println("Object " + id + " finalized");
    }
}

public class Main {
    public static void main(String[] args) {
        Demo d1 = new Demo(1);
        Demo d2 = new Demo(2);

        d1 = null;
        d2 = null;

        System.out.println("Requesting GC...");
        System.gc();

        System.out.println("End of main");
    }
}

Memory Information

public class Main {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();

        System.out.println("Total Memory: " + runtime.totalMemory());
        System.out.println("Free Memory: " + runtime.freeMemory());
        System.out.println("Max Memory: " + runtime.maxMemory());

        // Create many objects
        for (int i = 0; i < 10000; i++) {
            new String("Object " + i);
        }

        System.out.println("\nAfter creating objects:");
        System.out.println("Free Memory: " + runtime.freeMemory());

        // Request GC
        System.gc();

        System.out.println("\nAfter GC:");
        System.out.println("Free Memory: " + runtime.freeMemory());
    }
}

Best Practices

1. Don’t Use finalize():

// ✗ Bad (deprecated)
class Bad {
    @Override
    protected void finalize() {
        // Cleanup
    }
}

// ✓ Good (use try-with-resources)
class Good implements AutoCloseable {
    @Override
    public void close() {
        // Cleanup
    }
}

2. Explicit Cleanup:

class Resource {
    void open() {
        // Open resource
    }

    void close() {
        // Close resource
    }
}

// Usage
Resource r = new Resource();
try {
    r.open();
    // Use resource
} finally {
    r.close();
}

3. AutoCloseable Interface:

class MyResource implements AutoCloseable {
    void use() {
        System.out.println("Using resource");
    }

    @Override
    public void close() {
        System.out.println("Resource closed");
    }
}

// Usage with try-with-resources
try (MyResource resource = new MyResource()) {
    resource.use();
} // Automatically closed

Complete Example

// Modern approach - AutoCloseable
class DatabaseConnection implements AutoCloseable {
    private String connectionName;

    DatabaseConnection(String name) {
        this.connectionName = name;
        System.out.println("Connection opened: " + name);
    }

    void executeQuery(String query) {
        System.out.println("Executing: " + query);
    }

    @Override
    public void close() {
        System.out.println("Connection closed: " + connectionName);
    }
}

public class Main {
    public static void main(String[] args) {
        // Try-with-resources ensures cleanup
        try (DatabaseConnection conn = new DatabaseConnection("MyDB")) {
            conn.executeQuery("SELECT * FROM users");
        } // Automatically closed

        System.out.println("Done");
    }
}

Garbage Collection Types

Java has multiple GC algorithms:

  1. Serial GC: Single-threaded
  2. Parallel GC: Multi-threaded
  3. CMS (Concurrent Mark Sweep): Low pause
  4. G1 (Garbage First): Default in Java 9+
  5. ZGC: Ultra-low latency

Object Lifecycle

1. Created (new keyword)

2. In Use (has references)

3. Unreachable (no references)

4. Eligible for GC

5. finalize() called (if defined)

6. Memory reclaimed

Quick Reference

// Make object eligible for GC
Student s = new Student();
s = null;  // Eligible

// Request GC (not guaranteed)
System.gc();
Runtime.getRuntime().gc();

// finalize() (deprecated - don't use)
@Override
protected void finalize() throws Throwable {
    // Cleanup code
}

// Modern approach - AutoCloseable
class Resource implements AutoCloseable {
    public void close() {
        // Cleanup
    }
}

// Usage
try (Resource r = new Resource()) {
    // Use resource
} // Auto-closed

Comparison

Featurefinalize()try-with-resources
StatusDeprecatedRecommended
ExecutionUnpredictableGuaranteed
WhenBefore GCEnd of try block
ControlNo controlFull control
PerformanceSlowerFaster
ReliabilityUnreliableReliable

Exam Tips

Remember:

  1. Garbage Collection is automatic
  2. finalize() is deprecated (don’t use)
  3. System.gc() is a request, not command
  4. Object eligible when no references
  5. Use try-with-resources for cleanup
  6. Implement AutoCloseable interface
  7. Explicit cleanup methods better than finalize()
  8. finalize() not guaranteed to run
  9. finalize() runs before object destruction
  10. Modern approach: try-with-resources

Common Questions:

  • What is garbage collection?
  • What is finalize() method?
  • When is object eligible for GC?
  • How to request GC?
  • Why is finalize() deprecated?
  • What is alternative to finalize()?
  • What is try-with-resources?
  • How to implement AutoCloseable?