3.6 Available Memory

Status
Not open for further replies.

Davidelvig

Well-known member
How can I assess available memory on a Teensy 3.6? (and other Teensy versions)
If there are different "kinds of memory" that matter (e.g stack, heap) it would be good to know how to measure their availability.
I'm assuming I'm running out of "heap" space.

I've tried RamMonitorExample.ino, and it runs, but seems to be specific to Teensy 3.2 and below.
https://forum.pjrc.com/threads/32401-Memory-Status-and-Monitoring?highlight=rammonitor

If this is an easy answer, please point me to the method call documentation.

If not, I can post a test app the demonstrates the problem. (at the moment, it's a large app that demonstrated the issue... I'll need to untangle it).
My case now: creating a linked list of MIDI messages (objects) from a MIFI file.

My class for the message objects is currently defined as follows:
Code:
class midiMessage {
public:
    midiMessage(File *f, midiMessage *prev);
    
    void playMessage(void);
    void displayMessage(void);
    long getVarLenQuant(File *f, int *byteCount);
    
    midiMessage *_prevMessage = NULL,
                *_nextMessage = NULL;
    unsigned long timeFromStart = 0;
    unsigned long deltaTime = 0;
    unsigned char wholeMessageType = 0;
    unsigned char messageType = 0;
    unsigned char msgSubType = 0;
    unsigned long sysExLength = 0;
    unsigned char metaEventType = 0;
    
    unsigned char channel;
    int           fullMessageLength = 0;
    bool          isRunningMessage = false;
    unsigned char val1 = 0,
                  val2 = 0;
private:
    
};

at compile time, memory usage appears as...
Sketch uses 69864 bytes (6%) of program storage space. Maximum is 1048576 bytes.
Global variables use 26512 bytes (10%) of dynamic memory, leaving 235632 bytes for local variables. Maximum is 262144 bytes.
 
Last edited:
There are 3 basic allocation types: global/static, heap and stack/local.

The global/static variables are for anything you've made a global variable or anything that's declared static (even if local scope within a function). They are allocated at the beginning of RAM. This is the number Arduino shows when you compile.

The stack holds all the local variables, and temporary usage by interrupts. As you call more functions, it grows downward from the top of RAM.

The heap is all the stuff you've created at runtime with malloc() or C++ new. It starts allocating right after your global/static memory and grows upward. Hopefully the heap and stack don't hit head other!

Most people prefer to avoid heap usage for microcontroller programming, and the general strategy is to avoid big arrays on the stack. Arduino has a pretty strong convention of C++ objects with global scope. Doing it this way makes the usage visible in the compile message. If you haven't used the heap, then you only need to worry about whether your stack grows down took close to the global variables. If you don't ever use big arrays on the stack, it's unlikely to be an issue.

Of course you can use the heap and you can put lots of big stuff in local variables. It's just risky, especially if you ever reuse the code in another project.
 
Thanks!
The memory needs are not known until runtime (how many midi messages/events in a midi file). That makes heap ideal, I think (without pre-allocating for the largest-possible MIDI file).

Is there a way to measure the available heap, and I can check it prior to each malloc or C++ new?

Dave
 
Thanks FrankB. I expect C++ new() will return a NULL if it fails, as well.

I could use that as a signal of "out of memory", and that may be enough... I would just try to bail our gracefully at that point.
My concern would be that I malloc() or new() just little enough to get by, and then the stack overruns silently.

I think there's plenty of RAM to do what I need (load a mid-sized MIDI file into message nodes).
The files range from 5k bytes to 100 k bytes.

Is there an actual measure of heap space that can be checked before malloc() or new()?
 
Thanks, @manitou! This appears to be right on-point, especially https://forum.pjrc.com/threads/26559...8Teensy-3-1%29

The end of that thread seems to lead to a pull request
at https://github.com/PaulStoffregen/cores/commit/7f1f852b109b1c44e67b4c0d76cc19aef1aa25d6
... from March.

In it, an out-of-memory state causes a return of a (void *)-1 (and not NULL).

I may play with that to see if testing for malloc() = -1 prevents a crash.
I don't know how to do this yet with an object new(), where my code crashes (somewhere in the constructor).

Thanks for your help... there may be a fix in the code, though I need to poke around.
 
It seems clear now that I was new()-ing too many objects, and ran the heap into the stack.

Waiting until I get a NULL or (void *)-1 indicating a failed allocation is too late.

It has showed me, however, that the task I was attempting is not easily going to happen (loading a moderate-sized midi fill into RAM) with the space allowed on the Teensy 3.6.

So, I'm taking another path on this feature.

It would clearly be nice to know, however, how much RAM is available for runtime allocation, at least roughly, to be checked before malloc() or new().

Paul, is this on a wish list somewhere?
I've seen code in the base which seems to subtract the top-address-of-global memory from the bottom-address-of-stack to get such a number. It is the same code that returns a (void*)-1.
 
Status
Not open for further replies.
Back
Top