- JVM is a complete machine that runs on top of the real. It has its own machine instructions (assembly) and its APIs. Their role is to execute the generic instructions of machine in the operating system and in the specific hardware on which you are running.
- These virtual machine instructions are bytecodes. The bytecode name comes from the fact that each opcode (instruction) is the size of one byte and therefore the JVM is capable of running up to 256 different bytecode (although the Java 7 has only 205). This makes it a theoretically simple machine to implement and run on devices with limited capacity.
The JVM memory management is divided in:
- Stack or Code Cache: Native memory. Variable portion of memory that is used by the Java process to manage the applications and features made in Java that are running the JVM. It is a space used for compilation. It’s here that is native, made specifically for the system.
- Heap: It is the total area used to create and store all instances. You may have a fixed size or a minimum value (Xms) and maximum (Xmx).
- The JVM allocates on operating system the amount of Xms memory for once, and this memory is never returned to the system.
- As more memory is required, the JVM allocates in large blocks until the maximum of Xmx (if you need more than that, an OutOfMemoryError is thrown).
- Permanent Generation or PermGen¹: is a memory space counted out of the heap (in addition to Xms/Xmx) where information is stored for loading classes and methods. This memory can have a maximum value, but not necessarily will use it all. To specify the size of PermGen, use another option, the -XX:MaxPermSize
¹ – Until Java 7
- MetaSpace²: It is the representation of the class metadata. Came to replace the PermGen because among other things, it uses native memory, being limited only by the total system memory. The MetaSpace is able to dynamically resize the maximum size depending on the application needs on runtime. However, you can specify the maximum size with the option -XX:MaxMetaspaceSize
² – Java 8+
It is the component responsible for the release of the memory that is no longer being used. There are several algorithms for garbage collection, such as:
- The GC travels through memory and mark all objects accessible by the current threads.
- Then sweeps again the memory, collecting objects that have not been marked in the previous phase.
- Runtime: Periodically.
Generational Copying (Generational Hypothesis)
- Important: The current JVMs use this algorithm as principal.
- The generational hypothesis teaches that about 95% of the objects created during execution of the program is short-lived, while the remaining 5% usually have long life.
- The heap memory is divided into two generations: Young Generation (YG) and Old Generation (OG), which has a much larger space than YG.
- All new objects are allocated in YG and GC constantly scans the YG.
- Once the YG is full, the “living” objects found in the scan are copied to the OG through the process called minor collect, and all the YG space becomes available again for allocation.
- The “non-living” objects are not truly erased from memory. GC only marks the memory as available.
- Less often, are executed major collects, which also collect the OG using the mark-and-sweep. Major collects are also called FullGC, and usually take much longer, since sweep all memory.
- There is no more reason to not program right. There was a very common myth that we stress the GC if we create many objects. The algorithms are adapted according to the generational hypothesis, it’s better have many small objects that soon become unnecessary, than few that take long time to get out of memory.
Source: Introdução À Arquitetura e Design de Software (Introduction to Architecture and Software Design), https://www.casadocodigo.com.br/products/livro-arquitetura-java