How to check for RAM available?

23 Jan 2010

Besides calling malloc/free repeatedly as in the code below, is there any way to check how much RAM is available whilst running?

                // perform free memory check
                int blockSize = 16;
                int i = 1;
                printf("Checking memory with blocksize %d char ...\n", blockSize);
                while (true) {
                    char *p = (char *) malloc(i * blockSize);
                    if (p == NULL)
                        break;
                    free(p);
                    ++i;
                }
                printf("Ok for %d char\n", (i - 1) * blockSize);

Also, it is possible to work out from the compilation how much RAM is taken up by the program (is this as simple as the bin size)?

23 Jan 2010

Don't hold your breath!

I asked the same question back in November 2009 with the title "How big is my program?", but despite Simon's initial enthusiasm (see below), nothing has happened :-(.

Paul

Hi Paul,

Paul Griffith wrote:
How much RAM is available for programs? How much RAM is allocated to the stacks? Is it possible to detect stack overflow, or at least report the high water mark? Is dynamic memory allocation, such as malloc() supported? If so, how big is the pool?

I might ask you to hold that thought. The compiler does not report this information, but it sounds like something it should. We'll see if we can add this as a new feature.

At the same time i'll try and writeup a tutorial on memory/stacks/heaps, as it is an interesting area that is worthy of some proper explanation. It would also give context for the questions you are asking.

Some quickfire answers - if they don't make sense, then i'd wait until I get a chance to write up something properly.

Main RAM is 32k, with the RW/ZI regions at the bottom, and shared heap/stack filling the rest. Dynamic memory allocation is certainly usable (so malloc/free and new/delete both work fine). The memory will be allocated in the heap (and hence reduce the memory available for the stack).

More on this once we've had a chance to consider the possibility of the feature upgrade...

Simon

23 Jan 2010

Thanks Paul, at least I'm not the only one asking.

Simon - any progress on this?

Regards

Daniel

23 Jan 2010

This thread inspired me to do some investigation and so I made this script. Hope it helps.

24 Jan 2010 . Edited: 24 Jan 2010

Hi,

Daniel Peter wrote:
Simon - any progress on this?

Yep; we have something nice to display static usage in a branch of our compiler, but it is waiting in the wings until we get out the current update out, which is a general fix/stability update. Once this has passed our final testing, it'll be put live and we'll be in a position to merge and introduce this feature. But not before; stability takes priority over features for us.

As part of a "v2.0" library, we'll also be looking at what we can do about runtime/dynamic memory usage too.

Hope this is what you wanted to hear :)

Thanks,
Simon

25 Jan 2010
Igor Skochinsky wrote:

This thread inspired me to do some investigation and so I made this script. Hope it helps.

Thanks Igor, it could be very helpful and a nice way to learn something about Python.

Simon Ford wrote:

Hi Simon, that's good news. I'm using dynamic memory allocation for arrays and was wondering how big I could make them; I'm sure other people have the same issues in their code so some library functions could be useful.


Hope this is what you wanted to hear :)
30 Jan 2010

Thanks Igor, this is a very useful utility.

Paul

31 Jan 2010

I'm hijacking my own thread here, but in the absence of forum private messages I'm hoping Paul will see this ...

Paul Griffith wrote:
I want to used mbed to create a heating controller containing an embedded web server.

Hi Paul

I would like to do the same thing. I have written some ideas Home automation and would appreciate your comments and suggestions there.

Thanks
Daniel

31 Jan 2010

Instead of creating a new thread I thought I would post my question here.

It seems MALLOC does not reliabiliy return NULL if its cannot allocate memory on my unit, it tends to just CRASH.

Does anyone have any insight on this?

31 Jan 2010 . Edited: 31 Jan 2010

Hi Sean,

Sean Tate wrote:
It seems MALLOC does not reliabiliy return NULL if its cannot allocate memory on my unit, it tends to just CRASH.

If possible, could you provide a test case that reproduces this and we'll investigate.

Thanks,
Simon

04 Mar 2010
Simon Ford wrote:
If possible, could you provide a test case that reproduces this and we'll investigate.

Hi Simon

I didn't spot this before but I just tried to use my code at the top of this thread, and I think there is now a problem with malloc() as Sean says, and it may have been introduced with the compiler changes?

You can test it with this code:

#include "mbed.h"

int main() {
    printf("Hello world\n");

    // perform free memory check
    int blockSize = 256;
    int i = 1;
    printf("Checking memory with blocksize %d char ...\n", blockSize);
    while (true) {
        char *p = (char *) malloc(i * blockSize);
        printf("%d\n", i);
        if (p == NULL)
            break;
        free(p);
        ++i;
    }
    printf("Ok for %d char\n", (i - 1) * blockSize);

}

It prints out a series of integers but never gets to the final printf.

Could you look into this please? If I don't see a response here, I'll cross post under bugs.

Thanks
Daniel

05 Mar 2010

Hi Daniel,

Perfect. Made it nice and easy to reproduce. Here is an modified version which shows the problem and what actually happens:

#include "mbed.h"

extern "C" void HardFault_Handler() { printf("Hard Fault!\n"); while(1); }

int main() {
    printf("Hello world\n");

    // perform free memory check
    int blockSize = 256;
    int i = 1;
    
    printf("Checking memory with blocksize %d char ...\n", blockSize);
    while (true) {
        char *p = (char *) malloc(i * blockSize);
        printf("%d @ 0x%08X\n", i * blockSize, p);
        if (p == NULL)
            break;
        free(p);
        ++i;
    }
    printf("Ok for %d char\n", (i - 1) * blockSize);
}
The result is:

Hello world
Checking memory with blocksize 256 char ...
256 @ 0x100002A0
512 @ 0x100002A0
768 @ 0x100002A0
:
:
31488 @ 0x100002A0
31744 @ 0x100002A0
32000 @ 0x100002A0
Hard Fault!
So from this it is obvious it is not correctly checking the end of the heap limit. Another good ticket and a test for our test rig we're building.

Simon

05 Mar 2010

Thanks for following up on this Daniel.

 

Simon,

 

What is this HardFault_Handler()? Could it be used to programmitically reset the LPC / MBED when something like this happens?

31 Mar 2010

Its been a month since i asked the above question... Bump?

31 Mar 2010

Hi Sean, All,

The HardFault_Handler() could certainly be used to detect a condition where you may want to programatically reset. A hard fault will be triggered by thingslike trying to fetch data from an invalid address. See:

I think the LPC might have a way to internally reset without using a watchdog, but you'd need to look in to that more. Alternatively, you can request the mbed interface reset by using a function:

extern "C" void mbed_reset();

mbed_reset(); // ask the interface for a full mbed system reset, equivalent to pressing the button
Also, our next compiler update now includes RAM usage stats; it is currently in final testing along with the other updates, so if anyone wants to get a sneak peak and help us with some user testing, just send Dan a message.

Simon

31 Mar 2010 . Edited: 31 Mar 2010

[I wrote this between seeing your (Sean's) post, and Simon's Reply]

I think this is a job for the watchdog. I personally feel that  this is good practice anywhere you have dynamic memory allocation. Here's a little example I threw together:

 

#include "mbed.h"

// Simon's Watchdog example

class Watchdog {
public:
    void kick(float s) {
        LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
        uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4 
        LPC_WDT->WDTC = s * (float)clk;         
        LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset        
        kick();
    }
    
    void kick() {
        LPC_WDT->WDFEED = 0xAA;
        LPC_WDT->WDFEED = 0x55;
    }
};

Watchdog wdt;
DigitalOut heartbeat(LED1);

// Watchdog service routine

void bad_dog(void)
{
    wdt.kick();    
    printf("Dog kicked\n");
}

int main() {
    Ticker service;
    
    printf("Reset!\n");
    
    wdt.kick(5.0);          // 5 second timeout on watchdog - to make it visible
    
    service.attach(&bad_dog, 2);
    
    // perform free memory check
    int blockSize = 256;
    int i = 1;
    
    printf("Checking memory with blocksize %d char ...\n", blockSize);
    while (true) {
        char *p = (char *) malloc(i * blockSize);
        printf("%d @ 0x%08X\n", i * blockSize, p);
        if (p == NULL)
            break;
        free(p);
        ++i;
        wait(0.25);
        heartbeat = !heartbeat;
    }
    printf("Ok for %d char\n", (i - 1) * blockSize);
}
06 Apr 2010

You can also reset using NVIC_SystemReset().

21 May 2010
Sean Tate wrote:

Instead of creating a new thread I thought I would post my question here.

It seems MALLOC does not reliabiliy return NULL if its cannot allocate memory on my unit, it tends to just CRASH.

Does anyone have any insight on this?

Sean I checked your test code. Seems that you call printf after malloc in a loop.

while (true) {
        char *p = (char *) malloc(i * blockSize);
        printf("%d\n", i); <<<------ you call printf here

The majority of the printf library implementations use malloc internally to allocate memory for the formatted text. This explains why you did not see the last text provided that the last printf attempt is unable to allocate memory.

31 May 2010 . Edited: 31 May 2010
Simon Ford wrote:
So from this it is obvious it is not correctly checking the end of the heap limit. Another good ticket and a test for our test rig we're building.

Hi Simon

Can some priority be given to fixing this malloc bug in the compiler? In the absence of any other runtime ways of determining memory usage, it makes programming with dynamically allocated objects very difficult - if I run out of memory I get a crash, not even a hard fault sometimes, and I don't see this as acceptable. As I keep adding functionality to my application, I would like to know how much headroom in RAM I have, so if nothing else I can decide if my code needs memory optimisation.

In terms of static allocation, I would still like to see the memory usage statistics at compile time split into separate figures for AHBSRAM0 and AHBSRAM1, since this RAM is not usable by the heap. For example, if you compile a program with the LWIP library included, then it looks like one is losing lots of RAM, but it is being allocated from AHBSRAM1.

Thanks
Daniel

31 May 2010

I just looked through our trunk; looks like the AHBSRAM issue is fixed so will come when we next update the compiler (which will be sometime after we've rolled out the new cookbook, which we'll probably put live next week).

I've already raised the malloc behaviour with the core compiler team and after working with them it was definitely not something that was an obvious fix so we'll need to look at this one more closely. I'll make sure we further investigate the malloc behaviour after the next library release; probably also next week.

I'll give you a message as soon as we make any progress on this.

Simon

18 Jun 2010

Just a little bump on this to say that the malloc issue has not been forgotten, and that we're looking at it now. Cannot promise anything about a resolution, but it is being investigated.

21 Jun 2010

Thanks Jon, much appreciated.

Regards
Daniel

11 Sep 2010
user avatar Jon Ward wrote:
it is being investigated

Hi

Any resolution on this issue?

Thanks
Daniel

15 Sep 2010

Sorry about that - I believe that this is fixed in the newer version of the compiler, which is available in Beta mode.

24 Sep 2010

Hi Jon

I've tested this in beta mode and it looks to be fixed. Thanks for your efforts.

Regards
Daniel

27 Sep 2010

Hi Jon

I might have spoke too soon; code that worked last week now no longer works? Not sure why, so this might still be an open issue.

Regards
Daniel

26 Jan 2011

I appear to still be experiencing this problem (crash on malloc, without a hard fault in my case). Was there ever a resolution?

26 Jan 2011

Hi John

Have a look at the thread here.

It was fixed sort of a while ago but Hendrik found a way to break it!

Regards Daniel

26 Jan 2011

Hi John,

This should be fixed. One thing to check is you have the latest mbed library (27) - click on it in your program to see the version, and optionally update. If you are still having problems, perhaps you could share an example.

As an aside, note that functions like malloc are not going to be re-entrant, so it is worth considering where it may be getting called from to avoid problems (e.g. not interrupt routines)

Thanks, Simon

01 Feb 2011

I still appear to be hitting this problem. I have print statements each side of a malloc, the one before gets printed and the one after doesn't. My code is rather on the large side in terms of length, but the total static RAM usage is only 29%, so I don't see why I'd be running out so quickly while the code is running.

I can streamline my code if needed, but the main issue is that I have no way to capture out-of-memory errors. It simply stops once it reaches the malloc, no flashing lights or any such.

The strangest thing is that the error is forced by me including a call to rise on an InterruptIn object earlier in the code. I'm pretty sure I allocate more memory (after the crash point) than InterruptIn can possibly be using, and I have no problems.