C Program on Linux to exhaust memory

20,376

Solution 1

You should write to the allocated blocks. If you just ask for memory, linux might just hand out a reservation for memory, but nothing will be allocated until the memory is accessed.

int main()
{
        while(1)
        {
                void *m = malloc(1024*1024);
                memset(m,0,1024*1024);
        }
        return 0;
}

You really only need to write 1 byte on every page (4096 bytes on x86 normally) though.

Solution 2

Linux "over commits" memory. This means that physical memory is only given to a process when the process first tries to access it, not when the malloc is first executed. To disable this behavior, do the following (as root):

echo 2 > /proc/sys/vm/overcommit_memory

Then try running your program.

Solution 3

In my machine, with an appropriate gb value, the following code used 100% of the memory, and even got memory into the swap. You can see that you need to write only one byte in each page: memset(m, 0, 1);, If you change the page size: #define PAGE_SZ (1<<12) to a bigger page size: #define PAGE_SZ (1<<13) then you won't be writing to all the pages you allocated, thus you can see in top that the memory consumption of the program goes down.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PAGE_SZ (1<<12)

int main() {
    int i;
    int gb = 2; // memory to consume in GB

    for (i = 0; i < ((unsigned long)gb<<30)/PAGE_SZ ; ++i) {
        void *m = malloc(PAGE_SZ);
        if (!m)
            break;
        memset(m, 0, 1);
    }
    printf("allocated %lu MB\n", ((unsigned long)i*PAGE_SZ)>>20);
    getchar();
    return 0;
}

Solution 4

A little known fact (though it is well documented) - you can (as root) prevent the OOM killer from claiming your process (or any other process) as one of its victims. Here is a snippet from something directly out of my editor, where I am (based on configuration data) locking all allocated memory to avoid being paged out and (optionally) telling the OOM killer not to bother me:

static int set_priority(nex_payload_t *p)
{
    struct sched_param sched;
    int maxpri, minpri;
    FILE *fp;
    int no_oom = -17;

    if (p->cfg.lock_memory)
        mlockall(MCL_CURRENT | MCL_FUTURE);

    if (p->cfg.prevent_oom) {
        fp = fopen("/proc/self/oom_adj", "w");
        if (fp) {
            /* Don't OOM me, Bro! */
            fprintf(fp, "%d", no_oom);
            fclose(fp);
        }
    }

I'm not showing what I'm doing with scheduler parameters as its not relevant to the question.

This will prevent the OOM killer from getting your process before it has a chance to produce the (in this case) desired effect. You will also, in effect, force most other processes to disk.

So, in short, to see fireworks really quickly...

  1. Tell the OOM killer not to bother you
  2. Lock your memory
  3. Allocate and initialize (zero out) blocks in a never ending loop, or until malloc() fails

Be sure to look at ulimit as well, and run your tests as root.

The code I showed is part of a daemon that simply can not fail, it runs at a very high weight (selectively using the RR or FIFO scheduler) and can not (ever) be paged out.

Solution 5

Have a look at this program. When there is no longer enough memory malloc starts returning 0

#include <stdlib.h>
#include <stdio.h>

int main()
{
  while(1)
  {
    printf("malloc %d\n", (int)malloc(1024*1024));
  }
  return 0;
}
Share:
20,376
Mark
Author by

Mark

Updated on July 09, 2022

Comments

  • Mark
    Mark almost 2 years

    I would like to write a program to consume all the memory available to understand the outcome. I've heard that linux starts killing the processes once it is unable to allocate the memory.

    Can anyone help me with such a program.

    I have written the following, but the memory doesn't seem to get exhausted:

    #include <stdlib.h>
    
    int main()
    {
            while(1)
            {
                    malloc(1024*1024);
            }
            return 0;
    }
    
  • Mark
    Mark over 14 years
    Thanks for the info. I did that. but still the memory usage is only 1-2%.
  • Mark
    Mark over 14 years
    Thanks. The memory decreases on the system to a certain extent. After that the program crashes(segfault)
  • Mark
    Mark over 14 years
    Why is that if I run the program mentioned above the machine hangs, but if I use the memory allocated my malloc, the program gets segfault?
  • alesplin
    alesplin over 14 years
    It's likely that this is not exhausting memory, since it's not doing anything with the memory it's allocating (see above comments on optimistic memory allocation/use), but rather acting as a normal fork-bomb and exhausting the system's ability to context-switch.
  • unwind
    unwind over 14 years
    @Mark: That is very probably because malloc() returns NULL as it fails to allocate more memory, and you can't write to NULL.
  • JasonSmith
    JasonSmith over 14 years
    In other words, given youtube.com/watch?v=A7uvttu8ct0, your program is Jerry, and Linux is the woman at the car rental service.
  • Gunther Piez
    Gunther Piez over 14 years
    You need to write to a page, otherwise it won't be mapped to physical memory.
  • Andrii Yurchuk
    Andrii Yurchuk over 12 years
    @nos How can this code be updated to support the amount of memory I want to consume as a parameter from standard input, and the period of time it should stay allocated?
  • badp
    badp almost 11 years
    As Raymond Chen likes to say, once you run on root you are on the other side of the airtight hatchway and you're already pwned. I really hope the kernel doesn't let non-root processes lower their oom_adj stat, just like they can't lower their nice.
  • Tim Post
    Tim Post almost 11 years
    @badp No, you have to be root (but also must be root to adjust system paging & swap settings, etc). It's possible to write a rogue program to eat all memory, but you must be UID 0 for it to run effectively, whichever way you go.
  • David C. Rankin
    David C. Rankin almost 7 years
    If you use the proper format specifier (e.g. '%p') to print the pointer address, you eliminate the need for a cast. There is never a need to cast the return of malloc. See: Do I cast the result of malloc? for thorough explanation.