Programing

malloc은 Linux (및 기타 플랫폼)에서 할당을위한 백업 페이지를 느리게 생성합니까?

lottogame 2020. 11. 22. 18:49
반응형

malloc은 Linux (및 기타 플랫폼)에서 할당을위한 백업 페이지를 느리게 생성합니까?


Linux에서 내가했다면 malloc(1024 * 1024 * 1024)malloc은 실제로 무엇을합니까?

할당에 가상 주소를 할당한다고 확신하지만 (필요한 경우 무료 목록을 확인하고 새 매핑을 생성하여) 실제로 1GiB 상당의 스왑 페이지를 생성합니까? 아니면 mprotect주소 범위이고 실제로 터치 할 때 페이지를 생성 mmap합니까?

(저는 표준 이 이러한 종류의 세부 사항에 대해 침묵 하기 때문에 Linux를 지정 하고 있지만 다른 플랫폼도 무엇을 수행하는지 알고 싶습니다.)


Linux는 일명 지연된 페이지 할당을 수행합니다. '낙관적 메모리 할당'. malloc에서 얻은 메모리는 아무것도 지원하지 않으며이를 만지면 실제로 OOM 조건 (요청한 페이지에 대한 스왑 공간이없는 경우)이 발생할 수 있으며이 경우 프로세스가 예기치 않게 종료됩니다 .

예를 들어 http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html을 참조하십시오 .


9. 메모리 ( Linux 커널일부 , Andries Brouwer 의 Linux 커널에 대한 몇 가지 설명 )는 좋은 문서입니다.

여기에는 Linux의 실제 메모리 대 실제 메모리 처리를 설명하고 커널의 내부를 설명하는 다음 프로그램이 포함되어 있습니다.

일반적으로 첫 번째 데모 프로그램은 malloc ()이 NULL을 반환하기 전에 매우 많은 양의 메모리를 얻습니다. 두 번째 데모 프로그램은 이전에 얻은 메모리가 실제로 사용되므로 훨씬 적은 양의 메모리를 얻게됩니다. 세 번째 프로그램은 첫 번째 프로그램과 동일한 많은 양을 얻은 다음 메모리를 사용하려고 할 때 종료됩니다.

데모 프로그램 1 : 메모리를 사용하지 않고 할당합니다.

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

int main (void) {
    int n = 0;

    while (1) {
        if (malloc(1<<20) == NULL) {
                printf("malloc failure after %d MiB\n", n);
                return 0;
        }
        printf ("got %d MiB\n", ++n);
    }
}

데모 프로그램 2 : 메모리를 할당하고 실제로 모든 것을 터치합니다.

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

int main (void) {
    int n = 0;
    char *p;

    while (1) {
        if ((p = malloc(1<<20)) == NULL) {
                printf("malloc failure after %d MiB\n", n);
                return 0;
        }
        memset (p, 0, (1<<20));
        printf ("got %d MiB\n", ++n);
    }
}

데모 프로그램 3 : 먼저 할당하고 나중에 사용합니다.

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

#define N       10000

int main (void) {
    int i, n = 0;
    char *pp[N];

    for (n = 0; n < N; n++) {
        pp[n] = malloc(1<<20);
        if (pp[n] == NULL)
            break;
    }
    printf("malloc failure after %d MiB\n", n);

    for (i = 0; i < n; i++) {
        memset (pp[i], 0, (1<<20));
        printf("%d\n", i+1);
    }

    return 0;
}

( Solaris 와 같이 잘 작동하는 시스템 에서 세 개의 데모 프로그램은 동일한 양의 메모리를 얻고 충돌하지 않지만 malloc ()은 NULL을 반환합니다.)


나는 같은 주제에 대한 비슷한 게시물에이 답변을주었습니다.

일부 할당자는 게으른가요?

This starts a little off subject (and then I'll tie it in to your question), but what's happening is similar to what happens when you fork a process in Linux. When forking there is a mechanism called copy on write which only copies the memory space for the new process when the memory is written too. This way if the forked process exec's a new program right away then you've saved the overhead of copying the original programs memory.

Getting back to your question, the idea is similar. As others have pointed out, requesting the memory gets you the virtual memory space immediately, but the actual pages are only allocated when write to them.

What's the purpose of this? It basically makes mallocing memory a more or less constant time operation Big O(1) instead of a Big O(n) operation (similar to the way the Linux scheduler spreads it's work out instead of doing it in one big chunk).

To demonstrate what I mean I did the following experiment:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites

real    0m0.006s
user    0m0.000s
sys 0m0.008s

The bigmalloc program allocates 20 million ints, but doesn't do anything with them. deadbeef writes one int to each page resulting in 19531 writes and justwrites allocates 19531 ints and zeros them out. As you can see deadbeef takes about 100 times longer to execute than bigmalloc and about 50 times longer than justwrites.

#include <stdlib.h>

int main(int argc, char **argv) {

    int *big = malloc(sizeof(int)*20000000); // Allocate 80 million bytes

    return 0;
}

.

#include <stdlib.h>

int main(int argc, char **argv) {

    int *big = malloc(sizeof(int)*20000000); // Allocate 80 million bytes

    // Immediately write to each page to simulate an all-at-once allocation
    // assuming 4k page size on a 32-bit machine.

    for (int* end = big + 20000000; big < end; big += 1024)
        *big = 0xDEADBEEF;

    return 0;
}

.

#include <stdlib.h>

int main(int argc, char **argv) {

    int *big = calloc(sizeof(int), 19531); // Number of writes

    return 0;
}

Malloc allocates memory out of blocks managed by libc. When additional memory is needed the library goes to the kernel using the brk system call.

The kernel allocates pages of virtual memory to the calling process. The pages are managed as part of resources owned by the process. Physical pages are not allocated when memory is brk'd. When the process accesses any memory location in one of the brk'd pages a page fault occurs. The kernel validates that the virtual memory has been allocated and proceeds to map a physical page to the virtual page.

Page allocation is not limited to writes and is quite distinct from copy on write. Any access, read or write, results in a page fault and mapping of a physical page.

Note that stack memory is automatically mapped. That is, an explicit brk is not required to map pages to virtual memory that is used by the stack.


On Windows, the pages are committed (that is, the free memory available goes down), but they will not actually be allocated until you touch the pages (either read or write).


On most Unix-like systems, it manages the brk boundary. The VM adds pages when hit by the processor. At least Linux and BSDs do this.

참고URL : https://stackoverflow.com/questions/911860/does-malloc-lazily-create-the-backing-pages-for-an-allocation-on-linux-and-othe

반응형