# What is the Garbage Collector


### AN INFORMAL DEFINITION

Technical articles sometimes talk about Java garbage collector pauses. Like other languages with automatic memory management, Java has a process that runs periodically to free up the memory that the program allocates.

All of the above can sometimes be a bit confusing for programmers who have never used a language with manual memory release, such as the C language.

First, let's briefly explain what this thing we call memory consists of. To simplify it, memory is composed of cells that exist in a solid or magnetic storage device that hasn't been around for many years. Each of these cells is called an **octet or byte**. What should matter to us now is that memory always has a finite size, even though the available memories today are much larger than those of 10 or 20 years ago.

It is not feasible for memory to grow indefinitely. Therefore, it must be cleaned on a regular basis. This is especially important if the application we are using is very large, in which case it uses a lot of memory.

Let's see an example with code:

```java
record Student(String firstName, String lastName, String dateOfBirth, String[] courses) {}
record Professor(String firstName, String lastName, String dateOfBirth, String[] courses) {}
```

The lines above define two different classes. A class or record is nothing more than a data structure, meaning a series of fields associated with the class.

But so far we have not allocated memory. We have simply indicated to the compiler what fields it will have to use when we define objects of those classes.

```java
Student alice = new Student("Alice", "Holland", "22072010", new String[]{"Mathematics", "Psychology"}); 
```

Now we are indeed allocating memory to store the values of the fields of this student. It has to be stored in memory, because later we will want to access them: `alice.lastName()`

Later on, we will surely want to define more classes related to the application; or more objects of already existing classes; or both.

What we want to imply with these class examples is that in a large application many different classes will be defined; and every time we create an object of that class we will have to allocate memory. That has always been the case.

In the world of computing, types of memory have varied, memories have become cheaper, but memory will always be needed. We are referring to the type of memory called volatile, that is, memory whose content is erased when the application ends.

And who takes care of all this if programmers don't do it? The answer is that it has to be the Java Virtual Machine (JVM). The JVM is the one responsible for allocating the necessary memory to store the objects we create in the program. And if we create so many objects in the program that we end up using all the available memory in the system, it will have to be freed; that is, the most logical thing would be to clear the memory of old objects that are no longer used.

However, Java programmers never do that. Who does it then? The answer again is the JVM. The JVM has a process called the Garbage Collector. In a very simplified way, we can say that it is responsible for clearing the memory associated with objects that are no longer being used.

```c
// We define the student structure
struct Student {
    char firstName[50];
    char lastName[50];
    char dateOfBirth[20];
};

int main() {
    // 1. MANUAL MEMORY ALLOCATION - In Java, this entire process is handled by the "new" operator
    // In C, we explicitly tell the operating system how many exact bytes we need.
    // We use 'malloc' (memory allocation) and calculate the size the structure occupies.
    struct Student *alice = (struct Student *)malloc(sizeof(struct Student));

    // We check if the memory could be allocated successfully
    if (alice == NULL) {
        printf("Error: not enough memory.\n");
        return 1;
    }

    // We fill in the student data
    strcpy(alice->firstName, "Alice");
    strcpy(alice->lastName, "Holland");
    strcpy(alice->dateOfBirth, "22072010");

    // 2. MANUAL MEMORY RELEASE - In Java, this is done by the garbage collector 
    // Attention! In C, the system will not clean this up for you. 
    // If you forget to call 'free', that memory remains occupied until you shut down the program (memory leak).
    free(alice);

    // It is good practice to set the pointer to NULL to avoid errors
    alice = NULL; 

    return 0;
}

```

#### GARBAGE COLLECTOR PAUSES

Garbage collector pauses are called the times this process takes to run. For any other process, we talk about the execution time of the process.

Why then in this case does it receive the name of pause? Because since we do not know when it is going to run, every time it does, it looks like a pause of the main program.

Some will think that calling it a pause is an exaggeration because it is very rare for it to last more than a few milliseconds. But you have to keep in mind that in applications of high concurrency, that is, those that can receive thousands of simultaneous requests, one millisecond is important.

The major drawback of the garbage collector is that it is **unpredictable**, because we do not know when it is going to run. That is why we speak of pauses in plural.

As a result of the above, Java or any other language with automatic memory management (Kotlin, Python, Javascript, C#, etc.) cannot be used in systems where it is necessary to know beforehand the amount of time each process will take. For example, in an operating system, there are so many different processes running simultaneously that it is important to know the maximum and minimum times of each process.

Another example often given is that of an airplane control system. In a few milliseconds an airplane can travel a fair distance, so it is important to know beforehand how long each process will take.

These systems in which a language with **manual memory management** must be used are called **hard real-time systems or critical systems**. The languages used are C, C++, or lately also Rust.

* * *

#### NEW GARBAGE COLLECTORS: FAREWELL TO LONG PAUSES

Traditionally, Java has been criticized for the interruptions caused when cleaning memory. However, **the evolution of Java has changed this landscape**.

**Modern versions** of the platform (from Java 11 onwards, and with very powerful improvements in Java 17 and 21) have introduced **Low-Latency Garbage Collectors**.

Among them, two stand out mainly:

1.  **G1 (Garbage-First):** Designed for large applications. It divides memory into small blocks and decides to clean those that accumulate the most garbage first, keeping pauses controlled and predictable (usually below a few tens of milliseconds).
    
2.  **ZGC (Z Garbage Collector) and Shenandoah:** They are the kings of modern low latency. They are capable of performing most of the cleaning work **while the application continues running in parallel**. This reduces pauses to a few *microseconds*, regardless of whether your application handles tens of gigabytes of RAM.
    

Thanks to these technologies, today Java is successfully used in high-frequency banking environments, stock exchanges, and enterprise systems where immediate response is critical.

* * *

#### ATTEMPTS TO CONTROL THE GARBAGE COLLECTOR

As we have already seen, it is not possible to know when the garbage collector is going to run. However, we can mitigate this unpredictability a bit by allocating more memory to the Java application. This is done by adding a parameter on the command line when starting the Java application:

```bash
java -Xmx512M -jar MiAplicacion.jar 
```

There is another parameter to tell the Java JVM what type of garbage collector we want it to use (for example, `-XX:+UseZGC`). In this way, we precisely adapt memory management to the resources and demands of our project.

* * *

#### HOW FAR THE NEW COLLECTORS GO: REAL-TIME YES, BUT CRITICAL NO

Thanks to the microsecond-level pause reduction offered by modern collectors like ZGC or Shenandoah, **Java has made its way with enormous success into real-time applications** (also known as *soft real-time*).

This includes high-frequency financial environments (such as stock trading platforms or stock exchanges) and large streaming systems or microservices where an almost instantaneous response is an indispensable commercial requirement.

However, **it is essential to clarify** that Java **must never be used in hard real-time critical applications**.

Systems such as life support medical devices (for example, pacemakers) or an airplane's flight control modules demand absolute mathematical guarantees that a process will execute within an exact and fixed timeframe, without exceptions. Garbage collection, no matter how optimized it is, remains an automated process inside a virtual machine (JVM) that can suffer unexpected events under extreme loads. For this reason, for human health or critical aerospace safety, engineers continue to rely exclusively on **deterministic manual-management programming languages** like C, C++ or Rust.
