C - Check currently available free RAM?
Solution 1
No, there's no standard C function to do that. There are some platform-specific functions you can use to perform certain types of queries (like working set size), but those probably won't be helpful, because sometimes memory which has been properly free()
d is still considered to be allocated by the OS because the malloc
implementation might keep the freed memory around in a pool.
If you want to check for memory leaks, I highly recommend using a tool like Valgrind, which runs your program in a virtual machine of sorts and can track memory leaks, among other features.
If you're running on Windows, you can use _CrtDbgReport
and/or _CrtSetDbgFlag
to check for memory leaks.
Solution 2
Linux glibc sysconf(_SC_AVPHYS_PAGES)
and get_avphys_pages()
These two glibc extensions should give you the available number of pages. We can then just multiply that by the pages size sysconf(_SC_PAGESIZE)
to find the total available memory in bytes.
main.c
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/sysinfo.h>
#include <unistd.h>
int main(void) {
/* PAGESIZE is POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/
* but PHYS_PAGES and AVPHYS_PAGES are glibc extensions. I bet those are
* parsed from /proc/meminfo. */
printf(
"sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lX\n",
sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)
);
printf(
"sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x%lX\n",
sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE)
);
/* glibc extensions. man says they are parsed from /proc/meminfo. */
printf(
"get_phys_pages() * sysconf(_SC_PAGESIZE) = 0x%lX\n",
get_phys_pages() * sysconf(_SC_PAGESIZE)
);
printf(
"get_avphys_pages() * sysconf(_SC_PAGESIZE) = 0x%lX\n",
get_avphys_pages() * sysconf(_SC_PAGESIZE)
);
}
Compile and run:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
sample output on my 32GiB RAM system:
sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x7CCFFC000
sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) = 0x6383FD000
get_phys_pages() * sysconf(_SC_PAGESIZE) = 0x7CCFFC000
get_avphys_pages() * sysconf(_SC_PAGESIZE) = 0x6383FD000
0x7CCFFC000 is a bit smaller than 32GiB, and is the total RAM. 0x6383FD000 is the available one.
man get_avphys_pages
says it gets its data from /proc/meminfo
.
Tested in Ubuntu 19.04.
Solution 3
If in your system malloc()
always allocates physical memory, you can call malloc()
repeatedly with sizes differing not by 1, but by successive powers of two. That'll be more efficient. Below is an example of how to do it.
If, on the other hand, malloc()
only allocates virtual address space without mapping physical memory into it, this won't give you what you want.
Sample code:
#include <stdio.h>
#include <stdlib.h>
void* AllocateLargestFreeBlock(size_t* Size)
{
size_t s0, s1;
void* p;
s0 = ~(size_t)0 ^ (~(size_t)0 >> 1);
while (s0 && (p = malloc(s0)) == NULL)
s0 >>= 1;
if (p)
free(p);
s1 = s0 >> 1;
while (s1)
{
if ((p = malloc(s0 + s1)) != NULL)
{
s0 += s1;
free(p);
}
s1 >>= 1;
}
while (s0 && (p = malloc(s0)) == NULL)
s0 ^= s0 & -s0;
*Size = s0;
return p;
}
size_t GetFreeSize(void)
{
size_t total = 0;
void* pFirst = NULL;
void* pLast = NULL;
for (;;)
{
size_t largest;
void* p = AllocateLargestFreeBlock(&largest);
if (largest < sizeof(void*))
{
if (p != NULL)
free(p);
break;
}
*(void**)p = NULL;
total += largest;
if (pFirst == NULL)
pFirst = p;
if (pLast != NULL)
*(void**)pLast = p;
pLast = p;
}
while (pFirst != NULL)
{
void* p = *(void**)pFirst;
free(pFirst);
pFirst = p;
}
return total;
}
int main(void)
{
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
printf("Total free: %zu\n", GetFreeSize());
return 0;
}
Output (ideone):
Total free: 266677120
Total free: 266673024
Total free: 266673024
Total free: 266673024
Total free: 266673024
Solution 4
If you can afford #ifdef'ing a debug version (possibly in an emulator!), you could just build a debug version of malloc/free that keeps track of the number of bytes currently in use, and "print" it periodically (again - only in the debug version, possibly under an emulator) on whatever output device you have for debugging (a led?), and see if it keeps increasing.
The standard trick is to allocate sizeof(size_t) more than requested, thus storing the size together with the newly allocated memory - but if you're writing a firmware I guess you know it already :)
So... do you have an emulator?
EDIT: I'm so used to computers running at GHz that it didn't occur to me at first, but of course another thing you can do is to just count the number of allocations, not their size -- I can't imagine how this could take too much memory to run.
Maestro
Updated on March 31, 2022Comments
-
Maestro about 2 years
I know how to use
malloc()
andfree()
to allocate memory, but is there also a standard C function to check how much memory is left, so I can call that periodically to make sure my code has no memory leaks?The only thing I can think of is calling
malloc(1)
in a endless loop until it returns an error, but shouldn't there be a more efficient way?-
Mike over 11 yearsWhy not just use valgrind on your program to check for leaks?
-
Ben over 11 yearsnote that calling malloc in an endless loop is likely to never fail since most systems only allocate memory on first touch.
-
Faruk Sahin over 11 yearsRelated : stackoverflow.com/questions/2513505/…
-
Fred Foo over 11 years@Ben: every
malloc
call reserves part of the virtual address space, so it will eventually return an error. -
Maestro over 11 years@Mike See my comment to Adam
-
Ben over 11 years@larsmans, True, in fact malloc also needs (physical) memory to keep track of the allocated blocs (even if you drop the pointers). So you cannot malloc forever. However, this doesn't help at all to know how much memory is left.
-
AlphaGoku over 6 yearsYou could find the address in Ram before you want an overflow to be detected.Write a specific value to it and keep watching it in main() to see if it is corrupted
-
fdk1342 over 5 yearsThere is no standard way. But your OS / compiler / c library may have some additional functions that may give you the information you want. Posting that information would be useful.
-
-
Maestro over 11 yearsThe program is firmware running on a Cortex M0 CPU, and uses a lot of ARM specific calls/instructions, so I think it would be hard to analyze for Valgrind, and I have barely enough memory on the device to run my own code, let alone to add a virtual machine.
-
Alex Reynolds over 11 yearsIn that case, measure how much memory you have at the start of execution and write wrapper functions around
malloc
andfree
to decrement and increment from your start point, as loreb suggests in another answer. -
AlfredD over 5 yearsThat doesn't take into account the extra bytes allocated by certain implementations for every malloc'ed buffer (for alignment purposes, or validating buffer overruns)
-
Alexey Frunze over 5 years@AlfredD malloc() wouldn't let you have those bytes anyway.