Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with free() on structs in C. It doesn't reduce memory usage

I'm having a problem with free() on a struct in my C program. When I look at /proc//statm before and after the free it doesn't seem to reduce. Am I using free() wrong in this case, or am I reading /proc//statm wrong?

Here is a test case which yields the problem:

struct mystruct {
    unsigned int arr[10000];
};

void mem() {
    char buf[30];
    snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid());
    FILE* pf = fopen(buf, "r");
    if (pf) {
        unsigned size; //       total program size
        unsigned resident;//   resident set size
        unsigned share;//      shared pages
        unsigned text;//       text (code)
        unsigned lib;//        library
        unsigned data;//       data/stack
        unsigned dt;//         dirty pages (unused in Linux 2.6)
        fscanf(pf, "%u %u %u %u %u %u", &size, &resident, &share, &text, &lib,         &data);
        printf("Memory usage: Data = %d\n", data*sysconf(_SC_PAGESIZE));
    }
    fclose(pf);
}

int main(int argc, char **argv) {
    mem();
    struct mystruct *foo = (struct mystruct *)malloc(sizeof(struct mystruct));
    mem();
    free(foo);
    mem();
}

The output is:

Memory usage: Data = 278528
Memory usage: Data = 282624
Memory usage: Data = 282624

When I would expect it to be:

Memory usage: Data = 278528
Memory usage: Data = 282624
Memory usage: Data = 278528

I've done a similar test with malloc'ing a (char *), then free'ing it and it works fine. Is there something special about structs?

like image 650
oprimus Avatar asked May 14 '11 23:05

oprimus


3 Answers

Your answer is right over here on Stack Overflow, but the short version is that, for very good reasons, the memory allocator does not return memory to the host OS but keeps it (internally in your program's data space) as a free list of some kind.

Some of the reasons the library keeps the memory are:

  • Interacting with the kernel is much slower than simply executing library code
  • The benefit would be small. Most programs have a steady-state or increasing memory footprint, so the time spent analyzing the heap looking for returnable memory would be completely wasted.
  • Internal fragmentation makes page-aligned blocks (the only thing that could be returned to the kernel) unlikely to exist, another reason not to slow the program down looking for something that won't be there.
  • Returning a page embedded in a free block would fragment the low and high parts of the block on either side of the page.
  • The few programs that do return large amounts of memory are likely to bypass malloc() and simply allocate and free pages anyway using mmap(2).
like image 71
DigitalRoss Avatar answered Oct 22 '22 16:10

DigitalRoss


Whenever free actually releases the memory is implementation dependent. So maybe free is not returning the memory right away when it's a big chunk on memory. I don't think it has anything to do with structs.

like image 43
Pablo Santa Cruz Avatar answered Oct 22 '22 16:10

Pablo Santa Cruz


Mainly for performance reasons, the allocated heap memory won't be returned to the OS after being freed. It will be marked as free though, and maybe later the kernel will get it back, or your program will allocate it and use it again.

I don't know what you used to alloc/free your (char *). The difference you've seen might be that your (char *) was allocated on the stack, and the release/free process it different than with the heap (stack memory management is a lot simpler).

like image 38
ack__ Avatar answered Oct 22 '22 15:10

ack__