Programing

malloc이 gcc에서 값을 0으로 초기화하는 이유는 무엇입니까?

lottogame 2020. 10. 18. 08:18
반응형

malloc이 gcc에서 값을 0으로 초기화하는 이유는 무엇입니까?


플랫폼마다 다를 수 있지만

gcc를 사용하여 컴파일하고 아래 코드를 실행하면 우분투 11.10에서 매번 0을 얻습니다.

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

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

calloc이 있는데 malloc이 이렇게 동작하는 이유는 무엇입니까?

때때로 원하지 않더라도 값을 0으로 초기화하는 것만으로도 원치 않는 성능 오버 헤드가 있다는 것을 의미하지 않습니까?


편집 : 아, 이전 예제는 초기화되지 않았지만 "신선한"블록을 사용했습니다.

내가 정확히 찾고 있던 것은 큰 블록을 할당 할 때 초기화하는 이유입니다.

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

    free(a);

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

OUTPUT: 3
        0 (initialized)

그러나 mallocing을 할 때 보안상의 이유가 있음을 지적 해 주셔서 감사합니다! (생각하지 마십시오). 물론 새로운 블록 또는 큰 블록을 할당 할 때 0으로 초기화해야합니다.


짧은 답변:

그렇지 않습니다. 귀하의 경우에는 0이됩니다.
(또한 테스트 케이스는 데이터가 0임을 표시하지 않습니다. 하나의 요소가 0 인 경우에만 표시됩니다.)


긴 답변 :

에 전화하면 다음 malloc()두 가지 중 하나가 발생합니다.

  1. 이전에 할당되고 동일한 프로세스에서 해제 된 메모리를 재활용합니다.
  2. 운영 체제에서 새 페이지를 요청합니다.

첫 번째 경우 메모리에는 이전 할당에서 남은 데이터가 포함됩니다. 그래서 그것은 0이 아닙니다. 이것은 작은 할당을 수행 할 때 일반적인 경우입니다.

두 번째 경우 메모리는 OS에서 가져옵니다. 이것은 프로그램의 메모리가 부족하거나 매우 큰 할당을 요청할 때 발생합니다. (귀하의 예에서와 같이)

문제는 다음과 같습니다 . OS에서 오는 메모리는 보안 상의 이유로 제로화됩니다 . *

OS가 메모리를 제공하면 다른 프로세스에서 해제되었을 수 있습니다. 따라서 메모리에는 암호와 같은 민감한 정보가 포함될 수 있습니다. 따라서 이러한 데이터를 읽는 것을 방지하기 위해 OS는 데이터를 제공하기 전에 제로화합니다.

* C 표준은 이것에 대해 아무것도 말하지 않습니다. 이것은 엄격히 OS 동작입니다. 따라서이 제로화는 보안이 중요하지 않은 시스템에있을 수도 있고 없을 수도 있습니다.


이에 대한 성능 배경을 더 많이 제공하려면 :

@R로. 주석에서 언급하면이 제로화 때문에 항상 + 대신 사용해야 calloc()합니다malloc()memset() . calloc()이 사실을 이용하여 별도의 memset().


반면에 이러한 제로화는 때때로 성능 병목 현상입니다. 일부 수치 애플리케이션 (예 : out-of-place FFT )에서는 엄청난 양의 스크래치 메모리를 할당해야합니다. 그것을 사용하여 알고리즘을 수행 한 다음 해제하십시오.

이러한 경우 제로화는 불필요하며 순수한 오버 헤드에 해당합니다.

내가 본 가장 극단적 인 예는 48GB 스크래치 버퍼를 사용하는 70 초 작업에 대한 20 초 제로화 오버 헤드입니다. (약 30 %의 오버 헤드.) (허용됨 : 컴퓨터에 메모리 대역폭이 부족했습니다.)

명백한 해결책은 단순히 메모리를 수동으로 재사용하는 것입니다. 그러나이를 위해서는 기존 인터페이스를 뚫고 나가야하는 경우가 많습니다. (특히 라이브러리 루틴의 일부인 경우)


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).


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.


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

From gnu.org:

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


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.


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!


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?


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.

참고URL : https://stackoverflow.com/questions/8029584/why-does-malloc-initialize-the-values-to-0-in-gcc

반응형