DEV Community

Liriel
Liriel

Posted on

Java Garbage Collector: Why Creating Objects Is Cheaper Than You Think

When many developers first hear about Java's Garbage Collector, they often associate it with one thing:

"Automatic memory management comes at the cost of performance."

This perception made sense twenty years ago.

Today, however, some of the largest systems in the world run on the JVM, handling millions of requests per second with strict latency requirements.

Companies like Netflix, Uber, LinkedIn, and many banks rely heavily on Java in production environments where performance is not optional.

So what changed?

The answer lies in understanding how the Java Garbage Collector actually works.


The Memory Problem Every Language Must Solve

Imagine the following code:

User user = new User();
Enter fullscreen mode Exit fullscreen mode

The application allocates memory for the User object.

Eventually, that object is no longer needed.

The question is simple:

Who is responsible for freeing that memory?

In languages such as C, the developer is responsible:

User* user = malloc(sizeof(User));

free(user);
Enter fullscreen mode Exit fullscreen mode

Forgetting to free memory causes leaks.

Freeing memory too early can lead to crashes and undefined behavior.

Java chose a different approach:

The JVM itself determines when an object is no longer reachable and automatically reclaims its memory.

This process is known as Garbage Collection.


How Does Java Know an Object Is Dead?

Java does not determine whether an object is alive based on variables or scope.

Instead, it uses a concept called reachability.

Consider:

User user = new User();
Enter fullscreen mode Exit fullscreen mode

The variable user references the object.

As long as that reference exists, the object is considered alive.

Now:

user = null;
Enter fullscreen mode Exit fullscreen mode

If no other references point to that object, it becomes unreachable.

Unreachable objects become candidates for garbage collection.

This approach is significantly safer than manual memory management because the JVM avoids both accidental deallocation and most memory corruption issues.


The Observation That Changed Everything

The JVM is built around an observation known as the Generational Hypothesis:

Most objects die young.

Surprisingly, this is true for the majority of modern applications.

Examples include:

  • HTTP request objects
  • DTOs
  • JSON parsing structures
  • Temporary strings
  • Stream operations
  • Intermediate collections

These objects often live for only a few milliseconds.

Meanwhile, objects that survive for longer periods tend to remain alive for a very long time:

  • Caches
  • Singleton services
  • Application configurations
  • Database connection pools

This observation fundamentally shaped the design of Java's Garbage Collectors.


The Heap Is Divided Into Generations

Instead of treating all objects equally, Java separates memory into generations.

Heap
│
├── Young Generation
│   ├── Eden
│   ├── Survivor 0
│   └── Survivor 1
│
└── Old Generation
Enter fullscreen mode Exit fullscreen mode

Eden: Where Objects Are Born

Almost every object starts its life in Eden Space.

new User();
new Order();
new Product();
Enter fullscreen mode Exit fullscreen mode

All of them are allocated inside Eden.

When Eden becomes full, the JVM triggers a Minor GC.


Minor GC

During a Minor GC, the JVM identifies which objects in Eden are still alive.

Dead objects are discarded immediately.

Live objects are copied to one of the Survivor spaces.

Eden → Survivor
Enter fullscreen mode Exit fullscreen mode

This process is extremely efficient because most objects are already dead.

Remember the Generational Hypothesis:

Most objects die young.

As a result, the JVM often removes the vast majority of objects during every Minor GC cycle.


Survivor Spaces

The JVM alternates between two survivor areas:

  • Survivor 0
  • Survivor 1

Objects bounce between these spaces while they survive multiple garbage collection cycles.

Each time an object survives, its age increases.

Age 1
Age 2
Age 3
...
Enter fullscreen mode Exit fullscreen mode

Eventually, the JVM decides that the object is probably long-lived.

At this point, it gets promoted.


Promotion to Old Generation

Objects that survive enough collection cycles are moved to the Old Generation.

Young Generation
        ↓
Old Generation
Enter fullscreen mode Exit fullscreen mode

Typical examples include:

  • Spring Beans
  • Caches
  • Singleton instances
  • Application configuration objects

These objects are expected to remain alive for much longer periods.


Major GC and Full GC

Cleaning the Old Generation is considerably more expensive.

This process is often called a Major GC.

In some situations, the JVM may need to collect the entire heap:

  • Young Generation
  • Old Generation
  • Metaspace

This is known as a Full GC.

Historically, Full GCs were among the most feared events in Java applications because they frequently paused the application for long periods.

Modern collectors significantly reduced this problem.


The Stop-The-World Moment

During certain phases of garbage collection, the JVM pauses all application threads.

This event is called:

Stop-The-World (STW)

While the JVM performs critical operations, application threads remain suspended.

The goal of modern collectors is not to eliminate these pauses entirely, but rather to make them extremely short and predictable.


Enter G1GC

Since Java 9, the default collector is Garbage First (G1).

Instead of dividing memory into large contiguous spaces, G1 divides the heap into many small regions.

+----+----+----+----+
| R1 | R2 | R3 | R4 |
+----+----+----+----+
| R5 | R6 | R7 | R8 |
+----+----+----+----+
Enter fullscreen mode Exit fullscreen mode

Some regions contain young objects.

Others contain old objects.

This design allows G1 to focus on collecting the regions that provide the highest memory recovery with the smallest pause times.

Hence the name:

Garbage First.


The Secret Behind Fast Object Allocation

One of the biggest misconceptions in Java is:

Creating objects is expensive.

In reality, object allocation in Java is often incredibly cheap.

Most allocations happen using a technique called Bump Pointer Allocation.

| Object A | Object B | Free Space |
                       ^
                    Pointer
Enter fullscreen mode Exit fullscreen mode

Creating a new object frequently means little more than:

pointer += object_size
Enter fullscreen mode Exit fullscreen mode

No complex memory search.

No traversal.

No expensive allocation algorithms.

Just moving a pointer forward.


Thread Local Allocation Buffers (TLAB)

The JVM goes even further.

Each thread often receives its own allocation area called a Thread Local Allocation Buffer (TLAB).

Instead of multiple threads competing for access to the heap, they allocate objects inside their own local buffers.

This dramatically reduces contention and synchronization overhead.

For most applications, object allocation becomes almost lock-free.


Sometimes the Object Never Exists

Modern JVMs perform sophisticated optimizations.

One of the most impressive is Escape Analysis.

public int sum() {
    Point point = new Point(10, 20);

    return point.x + point.y;
}
Enter fullscreen mode Exit fullscreen mode

If the JVM determines that point never escapes the method, it may avoid allocating the object entirely.

In some cases:

The object is never created.


Is Garbage Collection Free?

No.

Garbage Collection introduces overhead.

The JVM spends CPU cycles:

  • Identifying live objects
  • Moving objects
  • Compacting memory
  • Updating references

However, the trade-off has proven extremely successful.

Developers gain:

  • Memory safety
  • Higher productivity
  • Fewer crashes caused by invalid pointers
  • Simpler application code

Final Thoughts

The Garbage Collector is often described as a convenience feature.

In reality, it is much more than that.

The JVM combines decades of research in:

  • Allocation algorithms
  • Concurrent programming
  • Memory compaction
  • Cache locality
  • Latency reduction

Modern Java applications are not fast despite the Garbage Collector.

In many cases, they are fast precisely because of the engineering behind it.

The next time you write:

new User();
Enter fullscreen mode Exit fullscreen mode

remember that behind this single line, the JVM is leveraging decades of computer science research to make that operation as efficient as possible.


References

  • Oracle Java HotSpot Garbage Collection Tuning Guide
  • Oracle G1 Garbage Collector Documentation
  • Aleksey Shipilev — JVM Anatomy Quarks
  • Scott Oaks — Java Performance: The Definitive Guide
  • Plumbr Garbage Collection Handbook
  • OpenJDK Documentation
  • GCeasy JVM Performance Articles

Top comments (0)