JavaRush /Java Blog /Random EN /More about the garbage collector in Java

More about the garbage collector in Java

Published in the Random EN group
Hello! In the last lecture, we first became acquainted with the built-in mechanism of the Java language - the garbage collector. It operates in the background while your program is running, collecting objects that have become unnecessary, which will later be deleted. This way it frees up memory for creating new objects in the future. In this lecture we will take a closer look at the principle of its operation. For example, how and at what point does an object become unnecessary? And how does the garbage collector know about this? We will answer these questions :) Our lecture is more of an overview: this material does not need to be memorized. It is intended to broaden your horizons regarding the work of memory and the garbage collector, so it will be enough to read it and learn something new for yourself :) Let's go! The first thing you need to remember is that the garbage collector runs in parallel with your program . It is not part of it and functions separately: to describe this, in the last lecture we gave an analogy with a robot vacuum cleaner. In fact, this was not always the case. Previously, the garbage collector was designed in such a way that it worked in the same thread as your program. And according to some schedule, once every few minutes, it began checking for the presence of unnecessary objects in the program. The problem was that during this check and garbage collection, the program froze and did not execute. Imagine that you are sitting in an office working. But then a cleaning lady comes and needs to wash the floors in the room. She kicks you out from behind the computer for 5 minutes and you wait until she finishes cleaning. During this time you cannot work. This is roughly how garbage collectors used to work :) Later, this mechanism was changed, and now the garbage collector works in the background, without slowing down the work of the program itself. You already know that an object dies when there are no references left to it. But the garbage collector doesn't actually count references to . Firstly, it can be quite long. Secondly, it is not very effective. After all, objects can refer to each other! More about the garbage collector - 2The figure shows an example where 3 objects reference each other, but no one else references them. That is, they are not needed for the rest of the program to work. If the garbage collector were simply counting references, all these 3 objects would remain and would not free up memory: there are references to them! It can be compared to a spaceship. During the flight, the astronauts decided to check the list of spare parts for repairs and found among them a steering wheel and pedals from an ordinary car. They are clearly not needed here and take up extra space. Although these parts are connected and have some functions, within the framework of the operation of the spacecraft they are unnecessary garbage, which is better to get rid of. Therefore, Java decided to make the basis for garbage collection not counting references, but dividing objects into two types - reachable and unreachable. How to determine if an object is reachable? Everything ingenious is simple. An object is reachable if it is referenced by another reachable object. This results in a “chain of reachability”. It starts when the program starts and continues throughout the entire duration of its operation. It looks something like this: More about the garbage collector - 4The arrow in the figure indicates the executing code of our program. In code, for example in the main() method, references to objects are created. These objects can refer to new objects, those to some more, and so on. A chain of object links is formed . If an object can be reached through this chain of links to a “root link,” that is, one that is directly created in the executing code, it is considered reachable. In our picture they are indicated in blue. But if an object has fallen out of this chain, that is, none of the variables in the code currently being executed contains references to it, and it is also impossible to reach it through the “chain of links” - it is considered unreachable. In our program, two such objects are indicated in red. Please note: these “red” objects have links to each other. But, as we said earlier, the modern garbage collector in Java does not do reference counting. It determines whether an object is reachable or unreachable . Therefore, the two red objects in the picture will become his prey. Now let's look at the whole process from start to finish, and at the same time let's see how memory works in Java :) All objects in Java are stored in a special memory area called the heap . In ordinary language, a “heap” is a mountain of objects where everything is lying around in a jumble. But the heap in Java is not like that. It has a very logical and reasonable structure. One fine day, Java programmers discovered that all objects in their programs can be divided into two types - relatively speaking, simple objects and “long-lived” ones . “Long-lived” objects are those that have survived many garbage collections. Most often they will exist until the end of the program. As a result, the common heap, where all created objects are stored, was divided into several parts. The first part has a beautiful name - Eden (biblical “Garden of Eden”). This is a great name because this is where objects go after they are created. It is in this part that memory is allocated for new objects when we writenew. Many objects can be created, and when space runs out in this area, the first, “fast” garbage collection begins. It must be said that the garbage collector is very smart and chooses a work algorithm depending on what is more in the heap - garbage or working objects. If almost all objects are garbage, the collector marks the “live” objects and moves them to another memory area, after which the current area is completely cleaned up. If there is little garbage and most of it is occupied by living objects, it marks the garbage, cleans it, and arranges the remaining objects. We said “the collector marks the “living” objects and moves them to another memory location,” but which one? The memory area where all objects that survive at least one garbage collection are transferred is called Survival Space . Survival Space, in turn, is divided into generations . Each object is assigned a generation based on how many garbage collections it has experienced. If there is one, it belongs to “Generation 1”, if 5 – to “Generation 5”. Together, Eden and Survival Space form an area called Young Generation . In addition to Young Generation, there is another memory area in the heap - Old Generation (“old generation”). These are the very long-lived objects that have survived many garbage collections. It is more profitable to store them separately from all the others. And only when the Old Generation area is full, i.e. Even there are so many long-lived objects in the program that there is not enough memory, a complete garbage collection is performed. It processes not just one memory area, but generally all objects created by the Java machine. Naturally, it takes much more time and resources. That is why it was decided to store long-lived objects separately. When space runs out in other areas, so-called “rapid garbage collection” is carried out. It covers only one area, and due to this it is more economical and faster. At the end, when even the area for centenarians is already clogged, full cleaning enters the fray. Thus, the most “heavy” tool is used by the assembler only when it is no longer necessary. Schematically, the structure of the heap and cleaning looks like this: More about the garbage collector - 5