Why does malloc initialize the values to 0 in gcc?

CLinuxGccMalloc

C Problem Overview


Maybe it is different from platform to platform, but

when I compile using gcc and run the code below, I get 0 every time in my ubuntu 11.10.

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

int main()
{
    double *a = malloc(sizeof(double)*100)
    printf("%f", *a);
}

Why do malloc behave like this even though there is calloc?

Doesn't it mean that there is an unwanted performance overhead just to initialize the values to 0 even if you don't want it to be sometimes?


EDIT: Oh, my previous example was not initiazling, but happened to use "fresh" block.

What I precisely was looking for was why it initializes it when it allocates a large block:

int main()
{
    int *a = malloc(sizeof(int)*200000);
    a[10] = 3;
    printf("%d", *(a+10));

    free(a);

    a = malloc(sizeof(double)*200000);
    printf("%d", *(a+10));
}

OUTPUT: 3
        0 (initialized)

But thanks for pointing out that there is a SECURITY reason when mallocing! (Never thought about it). Sure it has to initialize to zero when allocating fresh block, or the large block.

C Solutions


Solution 1 - C

Short Answer:

It doesn't, it just happens to be zero in your case.
(Also your test case doesn't show that the data is zero. It only shows if one element is zero.)


Long Answer:

When you call malloc(), one of two things will happen:

  1. It recycles memory that was previous allocated and freed from the same process.
  2. It requests new page(s) from the operating system.

In the first case, the memory will contain data leftover from previous allocations. So it won't be zero. This is the usual case when performing small allocations.

In the second case, the memory will be from the OS. This happens when the program runs out of memory - or when you are requesting a very large allocation. (as is the case in your example)

Here's the catch: Memory coming from the OS will be zeroed for security reasons.*

When the OS gives you memory, it could have been freed from a different process. So that memory could contain sensitive information such as a password. So to prevent you reading such data, the OS will zero it before it gives it to you.

*I note that the C standard says nothing about this. This is strictly an OS behavior. So this zeroing may or may not be present on systems where security is not a concern.


To give more of a performance background to this:

As @R. mentions in the comments, this zeroing is why you should always use calloc() instead of malloc() + memset(). calloc() can take advantage of this fact to avoid a separate memset().


On the other hand, this zeroing is sometimes a performance bottleneck. In some numerical applications (such as the out-of-place FFT), you need to allocate a huge chunk of scratch memory. Use it to perform whatever algorithm, then free it.

In these cases, the zeroing is unnecessary and amounts to pure overhead.

The most extreme example I've seen is a 20-second zeroing overhead for a 70-second operation with a 48 GB scratch buffer. (Roughly 30% overhead.) (Granted: the machine did have a lack of memory bandwidth.)

The obvious solution is to simply reuse the memory manually. But that often requires breaking through established interfaces. (especially if it's part of a library routine)

Solution 2 - C

The OS will usually clear fresh memory pages it sends to your process so it can't look at an older process' data. This means that the first time you initialize a variable (or malloc something) it will often be zero but if you ever reuse that memory (by freeing it and malloc-ing again, for instance) then all bets are off.

This inconsistence is precisely why uninitialized variables are such a hard to find bug.


As for the unwanted performance overheads, avoiding unspecified behaviour is probably more important. Whatever small performance boost you could gain in this case won't compensate the hard to find bugs you will have to deal with if someone slightly modifies the codes (breaking previous assumptions) or ports it to another system (where the assumptions might have been invalid in the first place).

Solution 3 - C

Why do you assume that malloc() initializes to zero? It just so happens to be that the first call to malloc() results in a call to sbrk or mmap system calls, which allocate a page of memory from the OS. The OS is obliged to provide zero-initialized memory for security reasons (otherwise, data from other processes gets visible!). So you might think there - the OS wastes time zeroing the page. But no! In Linux, there is a special system-wide singleton page called the 'zero page' and that page will get mapped as Copy-On-Write, which means that only when you actually write on that page, the OS will allocate another page and initialize it. So I hope this answers your question regarding performance. The memory paging model allows usage of memory to be sort-of lazy by supporting the capability of multiple mapping of the same page plus the ability to handle the case when the first write occurs.

If you call free(), the glibc allocator will return the region to its free lists, and when malloc() is called again, you might get that same region, but dirty with the previous data. Eventually, free() might return the memory to the OS by calling system calls again.

Notice that the glibc man page on malloc() strictly says that the memory is not cleared, so by the "contract" on the API, you cannot assume that it does get cleared. Here's the original excerpt:

> malloc() allocates size bytes and returns a pointer to the allocated memory.
> The memory is not cleared. If size is 0, then malloc() returns either NULL, > or a unique pointer value that can later be successfully passed to free().

If you would like, you can read more about of that documentation if you are worried about performance or other side-effects.

Solution 4 - C

I modified your example to contain 2 identical allocations. Now it is easy to see malloc doesn't zero initialize memory.

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

int main(void)
{
    {
      double *a = malloc(sizeof(double)*100);
      *a = 100;
      printf("%f\n", *a);
      free(a);
    }
    {
      double *a = malloc(sizeof(double)*100);
      printf("%f\n", *a);
      free(a);
    }

    return 0;
}

Output with gcc 4.3.4

100.000000
100.000000

Solution 5 - C

From gnu.org:

> Very large blocks (much larger than a page) are allocated with mmap (anonymous or via /dev/zero) by this implementation.

Solution 6 - C

The standard does not dictate that malloc() should initialize the values to zero. It just happens at your platform that it might be set to zero, or it might have been zero at the specific moment you read that value.

Solution 7 - C

Your code doesn't demonstrate that malloc initialises its memory to 0. That could be done by the operating system, before the program starts. To see shich is the case, write a different value to the memory, free it, and call malloc again. You will probably get the same address, but you will have to check this. If so, you can look to see what it contains. Let us know!

Solution 8 - C

malloc doesn't initialize memory to zero. It returns it to you as it is without touching the memory or changing its value.

So, why do we get those zeros?

Before answering this question we should understand how malloc works:

When you call malloc it checks whether the glibc allocator has a memory of the requested size or not.

If it does, it will return this memory to you. This memory usually comes due to a previous free operation so it has garbage value(maybe zero or not) in most cases.

On the other hand, if it can't find memory, it will ask the OS to allocate memory for it, by calling sbrk or mmap system calls. The OS returns a zero-initialized page for security reasons as this memory may have been used by another process and carries valuable information such as passwords or personal data.

You can read about it yourself from this Link:

> Neighboring chunks can be coalesced on a free no matter what their > size is. This makes the implementation suitable for all kinds of > allocation patterns without generally incurring high memory waste > through fragmentation.

> Very large blocks (much larger than a page) are allocated with mmap > (anonymous or via /dev/zero) by this implementation

In some implementations calloc uses this property of the OS and asks the OS to allocate pages for it to make sure the memory is always zero-initialized without initializing it itself.

Solution 9 - C

Do you know that it is definitely being initialised? Is it possible that the area returned by malloc() just frequently has 0 at the beginning?

Solution 10 - C

Never ever count on any compiler to generate code that will initialize memory to anything. malloc simply returns a pointer to n bytes of memory someplace hell it might even be in swap.

If the contents of the memory is critical initialize it yourself.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSHHView Question on Stackoverflow
Solution 1 - CMysticialView Answer on Stackoverflow
Solution 2 - ChugomgView Answer on Stackoverflow
Solution 3 - CDan AloniView Answer on Stackoverflow
Solution 4 - CPraetorianView Answer on Stackoverflow
Solution 5 - CTomaszKView Answer on Stackoverflow
Solution 6 - Cuser418748View Answer on Stackoverflow
Solution 7 - CTonyKView Answer on Stackoverflow
Solution 8 - CMostafa WaelView Answer on Stackoverflow
Solution 9 - Cuser23743View Answer on Stackoverflow
Solution 10 - CFlyingGuyView Answer on Stackoverflow