-
Notifications
You must be signed in to change notification settings - Fork 64
Debugging
Eventually, we should distinguish between tips for debugging JS applications and Zephyr.js and its APIs themselves. But for now, let's just collect anything we can think of here.
There are a number of different ways memory is used in the Zephyr.js system. The Zephyr OS itself reserves some memory for its own use. Then there are some static structures we reserve in our Zephyr.js API code. In prj.mdef, we set HEAP_SIZE to reserve some space for calling task_malloc / task_free. Currently this is set to 4096 (4KB). Finally, JerryScript allocates a memory pool for the data structures it needs as your application runs. These last two are the places where you might run out of memory at run time.
When JerryScript runs out of pool memory, it writes 'exit' to the serial console and terminates. When our Zephyr heap runs out, it returns a NULL pointer to task_malloc and we should catch it; we should be able to recover or drop an operation without a hard fail.
If I suspect a memory leak, the way I usually debug it is to force it to happen faster. So I create a loop in my JavaScript to run the suspected faulty operation over and over. If you're leaking even one byte per operation, you will run out of memory in a few tens of thousands of calls. But really, the minimum allocation is something like 8 or 16 bytes (TODO: fill in exact details), so you will tend to run out of memory after at most 5000 calls. Usually I add a print statement to count each time I perform the operation, then I watch what count I got to before the 'exit'.
Once you can reproduce it like this, try to shrink down the amount of code that's getting repeated until you get it down to the smallest amount of code that reproduces the problem. Then you should be hot on the trail of the memory leak.
When it's the Zephyr heap that's running out instead, I've just added a feature to trace the malloc/free calls that Zephyr.js makes. We've wrapped all these calls with zjs_malloc and zjs_free, and now if you set TRACE=y when building, these will be redefined to also print messages like this:
zjs_add_callback:99: allocating 20 bytes (0xa800dc28)
...
zjs_remove_callback:136: allocating 20 bytes (0xa800dc28)
You can manually review the output and hopefully discover the problem. Here's how you use it:
$ make TRACE=y JS=samples/Timers.js