Object Lifecycle

Lesson 0020 — 45 min read

The Object Lifecycle encompasses the full lifespan of an object in memory — from initial allocation and construction, through usage, to final destruction and memory reclamation. Master runtime memory allocation, reference counting, garbage collection, and memory leak prevention across C++, Java, and Python.

The Four Lifecycle Stages

  1. Creation (Allocation & Initialization): Memory is reserved on the Stack or Heap, and constructor code initializes state.
  2. Usage: Methods are executed, and object fields are accessed by active application threads.
  3. Destruction / Garbage Collection: Objects going out of scope or losing active references are finalized (destructors run or GC flags unreachability).
  4. Memory Reclamation: Reserved bytes are returned to the OS or JVM heap free pool for future allocations.

1. Object Creation & Memory Allocation

Languages allocate memory differently between Stack (automatic scope management) and Heap (dynamic runtime lifetime).

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

public class Main {
    public static void main(String[] args) {
        // Stack holds reference 's' -> Heap holds Student object
        Student s = new Student("Raj");
        System.out.println(s.name);
    }
}
#include <iostream>
#include <string>
using namespace std;

class Student {
public:
    string name;
    Student(string n) : name(n) {}
};

int main() {
    // Stack object (automatic memory cleanup on scope exit)
    Student s1("Raj");
    cout << s1.name << "\n";

    // Heap object (dynamic allocation — MUST be deleted manually)
    Student* s2 = new Student("Aman");
    cout << s2->name << "\n";

    delete s2; // Explicit memory reclamation
    return 0;
}
class Student:
    def __init__(self, name):
        self.name = name

def main():
    # Variable 's' in local stack frame -> Heap object Student
    s = Student("Raj")
    print(s.name)

if __name__ == "__main__":
    main()

2. Reference Counting Mechanisms

Reference counting tracks the number of pointers/handles pointing to an object. When count drops to zero, the object can be safely reclaimed.

class Demo {}

public class Main {
    public static void main(String[] args) {
        Demo a1 = new Demo(); // Reference count = 1
        Demo a2 = a1;         // Reference count = 2

        a1 = null;            // Reference count = 1
        a2 = null;            // Reference count = 0 -> Unreachable, eligible for GC
    }
}
#include <iostream>
#include <memory>
using namespace std;

class Demo {};

int main() {
    // shared_ptr tracks reference count automatically
    shared_ptr<Demo> a1 = make_shared<Demo>(); // count = 1
    shared_ptr<Demo> a2 = a1;                  // count = 2

    a1.reset(); // count = 1
    a2.reset(); // count = 0 -> Destructor runs, heap memory freed
    return 0;
}
class Demo:
    pass

def main():
    a1 = Demo()  # Reference count = 1
    a2 = a1      # Reference count = 2

    a1 = None    # Reference count = 1
    a2 = None    # Reference count = 0 -> Reclaimed immediately by CPython
if __name__ == "__main__":
    main()

3. Destruction & Garbage Collection

How objects exit memory differs fundamentally between deterministic manual/RAII destruction (C++) and managed runtime garbage collection (Java / Python).

public class Main {
    public static void main(String[] args) {
        System.out.println("JVM GC runs automatically via Mark-Sweep-Compact.");
        // System.gc() is only a request to JVM, not a guarantee!
        System.gc();
    }
}
#include <iostream>
using namespace std;

class Demo {
public:
    Demo() { cout << "Constructor called\n"; }
    ~Demo() { cout << "Destructor called (Deterministic Cleanup)\n"; }
};

int main() {
    {
        Demo obj; // Stack object
    } // Destructor runs IMMEDIATELY here when exiting scope
    return 0;
}
import gc

class Demo:
    def __del__(self):
        print("Finalizer __del__ called")

def main():
    obj = Demo()
    del obj # Reclaims object if ref count hits zero
    gc.collect() # Trigger manual cyclic GC sweep

if __name__ == "__main__":
    main()

4. Memory Leaks in Object-Oriented Languages

A Memory Leak occurs when allocated memory is no longer needed by the program but cannot be reclaimed because unintentional references persist.

import java.util.ArrayList;
import java.util.List;

class MemoryLeakExample {
    // Static collection lives for entire application lifetime!
    private static List<Object> staticList = new ArrayList<>();

    public void leak(Object obj) {
        staticList.add(obj); // Objects added here NEVER get garbage collected!
    }
}
class MemoryLeakExample {
public:
    void leak() {
        int* ptr = new int(10);
        // Forgetting delete ptr -> Heap memory leak!
    }
};
class MemoryLeakExample:
    static_list = [] # Class-level list lives for program lifetime

    def leak(self, obj):
        self.static_list.append(obj) # Objects never freed!

5. Cyclic References & Solutions

A Cyclic Reference forms when two or more objects reference each other in a loop.

class Node {
    Node next;
}

public class Main {
    public static void main(String[] args) {
        Node a = new Node();
        Node b = new Node();
        a.next = b;
        b.next = a; // Cyclic reference formed

        a = null;
        b = null; // Java GC safely reclaims both nodes despite cycle!
    }
}
#include <iostream>
#include <memory>
using namespace std;

struct Node {
    // Solution: Use weak_ptr for 'next' or back-reference to break cycle!
    weak_ptr<Node> next;
};

int main() {
    shared_ptr<Node> a = make_shared<Node>();
    shared_ptr<Node> b = make_shared<Node>();

    a->next = b;
    b->next = a; // weak_ptr prevents ref count deadlocks
    return 0;
}
class Node:
    def __init__(self):
        self.next = None

def main():
    a = Node()
    b = Node()
    a.next = b
    b.next = a # Cyclic reference (reclaimed by Python cyclic GC)
    a = None
    b = None

if __name__ == "__main__":
    main()

Comparison Summary

Aspect Java C++ Python
Memory Allocation Heap (all objects) + Stack (reference variables) Stack (automatic) OR Heap (new / smart pointers) Heap (runtime managed) + Stack (scope handles)
Destruction Model Automatic Garbage Collector (Mark-Sweep-Compact) Deterministic Destructors (RAII) / manual delete Automatic Ref Counting + Cyclic GC
Ref Count Cycles Safely reclaimed via GC Root graph traversal Memory Leak! (Requires std::weak_ptr) Reclaimed by secondary cyclic GC module
Primary Leak Cause Static collections / unremoved event listeners Unfreed heap pointers (new without delete) Growing global lists/dicts / unevicted caches

What occurs in C++ when two objects hold std::shared_ptr references to each other in a loop?

How does Java handle cyclic references between unreachable objects?

Notes

Object Lifecycle :-

4 Stages ⇒ Creation (Allocation) — Usage — GC / Destruction — Memory Reclaimed

Memory Allocation :-

Stack ⇒ Automatic scope allocation ; ultrafast ; automatic cleanup on scope exit (C++ default)

Heap ⇒ Dynamic runtime allocation ; requires manual delete or smart pointers (C++) or GC management (Java/Python)

Destruction & GC :-

C++ ⇒ Deterministic RAII destructors (~Demo()) ; manual delete ; std::shared_ptr ref counting

Java ⇒ Reachability GC (Mark, Sweep, Compact) from GC Roots ; System.gc() is non-guaranteed request

Python ⇒ Primary Reference Counting + secondary cyclic GC

Cyclic References & Leaks :-

C++ Cycle Leak ⇒ shared_ptr loops keep ref count > 0 forever ; fix with std::weak_ptr

Java / Python Cycle Handling ⇒ Reclaimed automatically via GC graph traversal / cyclic collector

Java / Python Leak Cause ⇒ Unintentional static collection references or lingering event listeners

Primary source: Oracle Java Tutorials — Garbage Collection Tuning, cppreference — Smart Pointers & RAII & Python Docs — gc module. Ask me anything that's unclear.

← Prev: SOLID Principles Next: Advanced Keywords →

Questions? Ask your agent — you can follow up on any concept, quiz answer, or how this applies to a specific coding problem. Review the Java glossary or syntax quick reference for a compressed overview.