When using Mendix you will use it together with Java (JDK) to deploy and run the actual project in a Java Virtual Machine (“JVM”).
The Java Virtual Machine is a container in which the Mendix application is ran. It looks like this:
Or as shown in the Mendix Cloud:
The Permanent Generation (“PermGen”) holds classes and libraries. They are only loaded into the PermGen when they are actually used. It is not part of the Java Heap Space and in Java8 it no longer exists and is replaced by something called “Metadata”. These concepts mostly related to the libraries you add in the userlib directory of your project. Once they are used somewhere in a microflow (through a Java call) they will be added to the PermGen (Java 7 and prior) or the Metadata (Java 8). So if you see any errors related to these two terms, you know where to start looking.
Another interesting area is the “Stack”. This is what holds, among other things, all information about microflows, domain models and other Mendix specific information. Any microflow that is executed will also end up in the stack (see thread stacks in the graph above).
Heap and the GC. And OOM errors.
Next up is the heap space (“Heap”). But before we go into that. Let’s briefly discuss another important part of the JVM: the garbage collector (“GC”).
A GC is responsible for:
- allocating memory
- ensuring that any referenced objects remain in memory, and
- recovering memory used by objects that are no longer reachable from references in executing code.
Simply put, any object in the Heap that is currently in use (which is a fairly broad concept) is considered to be alive. Any object that is no longer used is considered dead. The GC takes care of removing all these dead objects to free up memory in the Heap again.
A GC is not responsible for preventing out of memory errors (“OOM errors”) in itself. You could for example keep creating objects indefinitely and since will stay alive until you are done doing so, the GC wouldn’t even touch those objects but you would still end up with an OOM error.
Back to the Heap. We can divide it into three parts:
- Eden space (young generation)
- Survivor space (young generation)
- Tenured generation (=old generation)
When the GC executes a minor garbage collect it will try to clean up all objects in the young generation only. If it fails to clean up an Eden space object it will move that object to the Survivor space. If it has failed to clean up a Survivor space object enough times, it will move it to the Tenured generation. If the Tenured generation grows large enough (around 60% of the total space available to the Heap) it will execute a major garbage collect and try to clean up all objects in both the young and the old generation. So a healthy JVM would have a Heap that goes up and down with regard to its memory usage in the various parts.
You can see this quite well in the following JVM Object Heap graph taken from the Mendix Cloud:
The purple and green spikes are minor garbage collects. The large drops in the red part are major garbage collects. This is healthy looking Heap.
And finally a Mendix Cloud graph where all of the above comes together:
The green (“apps”) part is basically the JVM in which the Mendix application is running. Anything else is reserved for the operating system of the application server.