Footprint of an application
When you are developing a Java application with MicroEJ, you may wonder about the footprint of your application. Memory consumption, for both RAM and ROM, is a sensitive point when developing an embedded system. This article will give you the keys to measure the footprint of your application.
Memory Map Analysis
Most linkers are able to generate a memory map file along with their binary output. There is no commonly adopted format for memory map files but you will find more or less the same kinds of information: symbols, created sections, memory layout, reserved sizes in both RAM and ROM memories, etc. Like IAR Embedded Workbench or GCC, MicroEJ generates such map files. They are important since they provide details about the footprint of the application.
When you execute your Java application on EmbJPF, there are two possible flows:
- The generic case is when using a development platform. The code is compiled and linked with the resources. An object file is generated and is named SOAR.o by default. This binary file is partially linked, some symbols are missing. You then have to link it with your C code and with the Java runtime (javaruntime.a ou javaruntime.lib) using your C environment to produce the final binary file to program your board.
- The special case is when using a kickstart platform. These platforms contain precompiled drivers and operating system so MicroEJ produces a fully linked binary file, generally named SOAR.out. You can then program the corresponding demonstration board with this file.
In both cases, MicroEJ generates a memory map file, generally named SOAR.map. Here are the generated files for the Hello World Java example, executed on the kickstart platform for STM3220G-EVAL demonstration board:
Memory map files are text files and by-hand analysis may be laborious. That’s why we have included a plugin in our IDE for a much more handy analysis. It is called the Memory Map Analyzer and you simply have to double-click on a memory map file to open it with the Memory Map Analyzer. A graphical representation of the file is then displayed:
For each category, you can see the memory consumption. Image size is for ROM memory, Runtime size is for RAM memory. You should often look at this file during development so as to keep an eye on the memory footprint of your application.
Remember the two possible flows. Well, this leads to two possible contents for the SOAR.map file:
- For kickstart platforms, the binary file is fully linked. Everything is included and the memory map file shows the total size of the application.
- For development platforms, the binary file is partially linked. Everything that is linked by the C environment is not included, such as the Java runtime, the drivers, the operating system, MicroUI’s back buffer and working buffer, etc. The memory map file reveals only the size of the Java part of the overall application. If you want to know the total size of the application, you have to look at the data generated by your C environment.
As an illustration, here is the memory map file for the same application as above but executed on another platform. Instead of the kickstart platform, the application is executed on the platform example called Basic for the same board. Compare it to the previous image:
For more information on the Memory Map Analyzer plugin, open the Help menu, click on Help content and select Memory Map Analyzer User Guide. You can also read section 10.1 Memory Map Analyzer from the document Platform Architecture – User Manual, available from the MicroEJ Resource Center.
Adjust heap and stack size
Reserved memory for heap and stacks appears in the memory map file but these areas may be not properly sized for your application and you will need to adjust them. Sizes can be adjusted in the Launch Configuration. See the document Platform Architecture ([version]) – User Manual, section 13.4.2 Category: Memory.
First, let’s talk about undersized heap and stack. You will find out very easily because you will get exceptions during execution on board. If the heap is too small,
OutOfMemoryErrors will be thrown; if the stacks are too small,
StackOverflowErrors will be thrown. Increase the size to solve this.
If heaps and stacks are oversized, you won’t get exceptions. Nevertheless you will want to adjust their sizes so as not to waste memory. There is currently no way to easily monitor the stack usage. Simply try to reduce the values until you get exceptions to find what the limit is. Since stacks are managed with blocks, this is not a difficult operation. On the opposite, it is easier to monitor the heap usage because Java provides appropriate methods. You simply have to call the method Runtime.freeMemory() to know the available memory in the heap and hence reduce the size to a reasonable value. Don’t forget to call System.gc() before calling
Runtime.freeMemory() so that useless objects are removed from memory before measurement. Note that you should not reduce it too much. Indeed, when the heap size is too adjusted, then garbage-collection will be needed very often and will impact the performances. Give the virtual machine a comfort zone.
You should be aware that memory leaks are possible in Java. Unlike C, it is not a memory zone that can no longer be accessed because all pointers to this zone are lost; it is because of objects that developers think they are no longer used but are in fact still referenced, somewhere in the application. Hence, they are not garbage-collected and consume heap memory for nothing.
When there are memory leaks, the heap will become full at some point and you will get an
OutOfMemoryError. As previously said, you can increase the size of the heap to quickly fix the exception issue but you won’t fix the real cause. If you find yourself increasing the size of the heap regularly, then you may have memory leaks in your application.
To track memory leaks, we provide a tool called the Heap Analyzer. When the application is executed in the simulator, it is possible to generate files that contain snapshots all the objects in the heap. There are called heap dumps and have a *. heap extension. Analyzing these files, looking at their content, comparing them, help to find memory leaks.
To activate heap dumping, select the correct option in the Launch Configuration of your application:
The generated *.heap files can then be analyzed with the Heap Analyzer. You will find more information about heap analysis in section 10.4 Heap Dumper & Heap Analyzer from the document Platform Architecture ([version]) – User Manual, available from the MicroEJ Resource Center. You can also open the Help menu, click on Help content and select Heap Analyzer User Guide.