Lua Memory Usage Tips

While lua APIs of the meter provides possibilities for users to implement their own features easily, it does come with some limitations, the most strict restriction might be the limited RAM. As many of you might know, unlike programming on a PC, where the RAM is basically free given, the microcontrollers has very limited RAM. The microcontroller of this project comes with a RAM size of 128KBytes, and the memory that the user could use is around 80KBytes so far. One used to programming on a PC could run out of RAM easily. However, by following some rules, the script can still be written to do complex work.

Memory Usage

The memory of the meter is used by lot of things, including:

  • Static allocated RAM in BSS section, which contains interrupt stack, USB buffers,screen GRAM and other frequently used buffers, the usage of this part is approximately 26KBytes now.

  • Stack for meter UI, background services(data collecting, fast-charge triggering, lua interpreter etc.), services for PC application, created by RTOS, this comes with a comsumption of approximately 20KBytes so far.

  • Approximately 80KBytes is free, this is the RAM your script could use.

Consider The Programming Language

At first glance, it seems that you could do lot of things with 80Kbytes of free RAM, considering that all the features of the meter is implemented with approximately 46 Kbytes of RAM, not mention that all the services is included, you could call them whenever you want.

But another factor should be take in consideration, that is, while all features of the meter is implemented in C, your features would be written in lua, which is a dynamic advanced language. While it provides super easy coding, it comes with a RAM usage of a few times larger than C. Just to get some feeling, a number type variable in lua (It’s float type equivalent on this platform) consumes 22bytes of RAM, 5 times larger than that in C !!

It’s the PEAK memory usage that matters

In embedded systems, which should be highly relieable, won’t accept any memory allocation failure. The meter is designed to STOP ALL THE OPERATION and pop up a memory failure dialog, there is no chance of recovery from this situation (also shouldn’t be) except a power cycle. As stated above, when an allocation failure happened, you have no chance to release your resources and try to recover, no opportunity to pop up your own dialog. This means that your task is to guarantee your PEAK memory usage doesn’t reach the red line.

Monitoring Memory Usage

If you are using the PC suite of the meter, you could monitor the memory usage on Lua Script panel. You can also get the memory usage in your code by calling: sys.gFreeHeap() to get currently free heap. sys.gFreeHeapEver() to get minimum free heap in history. sys.gTotalHeap() to get total heap size.

Tip1: Split your program into different files

When you try to run a script, the lua interpreter first load the WHOLE file in to the memory and compile it into byte code, add variables to the heap. This means at a some time, your script and the byte code of your script are both in the memory. Recall that only the peak memory usage matters, even the script loaded in memory is useless after translated into byte code, and will be uploaded at some point, the meter will not give it that chance.

Now consider you’re loading a 40Kbyte script file, let’s assume that it’s 40Kbytes bytecode after translated. The peak memory usage will be 80KBytes, which almost exhausted the RAM. To help solve this problem, you could simply split your program into different modules, load them one-by-one with require() in the lua language. Let’s assume you modularize your program into four 10Kbytes files, and each of those with 10Kbytes bytecode after compilation. After loading all the modules, the peak memory usage is no longer 80Kbytes but 10K+40K = 50Kbytes. Modularization is not just a good programming practice, it helped to solve peak RAM usage issue in this scenario.

Tip2: Pre-compile your module into byte code

While Tip1 works quite well enough in most cases, when you need more RAM desperately, you could prohibit the RAM peak usage caused by compile process completely. By issuing sys.gByteCode({path},[option]), you can convert your source code file into bytecode. A pre-compiled file with extension *.lc is generated in the same path of your input file. Use option parameter sys.RESERVE_DEBUG_INFO in the case when you don’t want to lose debug information.

Here’s some reference data to have an idea of how much RAM it could save: Tested with UI_demo source file of 5.23KBytes:

Scenario Peak RAM Consumption
*.lua directly 29.64KB
*.lc RESERVE_DEBUG_INFO 19.52KB
*.lc STRIP_DEBUG_INFO 16.00KB