Sometimes, you can see with
gc.mem_free() that you have plenty of memory available, but you still get a message “Memory allocation failed”. As described in a previous section, the memory manager and garbage collector work to clean up and identify available memory space. After running your program for a bit, your memory may become “fragmented”, meaning that there are only small contiguous areas of open memory space. While the total memory available may be sufficient for your new object, if there is no continuous memory space available the error is raised “Memory allocation failed”. (Note: Doing a “defragmentation” of memory is not feasible with the memory structure of CircuitPython, but there are things you can do to help reduce memory fragmentation.) Here are several strategies to reduce memory fragmentation to help retain space for allocating larger memory objects.
Call the garbage collector early and often
The garbage collector is triggered when the memory manager cannot find an free memory space to fit a new variable. But you can call the garbage collector into action in your own code to clear out unused variables and reduce memory fragmentation.
gc.collect() periodically in your code to free up the memory space from unused memory objects, especially in code locations immediately after memory items are dereferenced. If you are done with a variable, and use
del large_variable, call the garbage collector immediately.
After function returns
Using functions is a good way to “encapsulate” and free up your memory usage. After a function call returns from execution, all the local variables are immediately dereferenced and become “phantom” objects. After a function call that creates a lot of large variables, call
gc.collect() immediately to free up all the “phantom” memory objects that were dereferenced when the function returned. Each call to
gc.collect() will take some processor time but it can significantly reduce your memory fragmentation.
If you are reaching the limits of your memory, sprinkle in
gc.collect() in your code to help reduce memory fragmentation. After a function returns is always a great time to call
gc.collect() to free up space.
Before creating large memory objects
Another good time to call
gc.collect() is immediately prior to creating large objects. There could be “unused” phantom variables clogging up a space that could accommodate your new big variable. By running the garbage collector, you clear out those unused variables so the new memory allocation can be placed in that space.
Other techniques to reduce memory fragmentation:
- Use functions where it makes sense for memory items that are temporary. Take advantage of the fact that after a function closes, all its local variables are automatically “unused”. Call
gc.collect()after function returns to reclaim all that memory space as free again.
gc.collect()prior to any large memory allocations. This will help reduce the fragmentation since you clear out all phantom unused variables before you request a new chunk.
- For bitmaps and text labels that are static through your program, create them early in the life cycle ofyour code. If you allocate them toward the end, it is a higher chance that your memory will get fragmented and cause a memory allocation error when you later create the bitmap or text label. Allocate these large items early while memory space is relatively wide open.
- Changing text in a
labelcauses reallocation of the
label’s memory. Consider ways to avoid changing the text in your
- Special note with text labels:
bitmap_label.labeluses less overall RAM but it needs all its memory in one chunk. Somewhat counterintuitively,
label.labeluses more total RAM but splits it up into smaller pieces, so consider using label if you need to allocate text labels with frequently changing text. This is one way to “walk between the raindrops” when your memory is fragmented. If you really need to redo the text in a label frequently, evaluate whether
- Advanced programmers: Allocate a large memory buffer early in the life of your code and reuse the same memory buffer through your program.