#include <unistd.h>
#include <cstdlib>
int main()
{
for (int i=0; i<512*512*512; i++)
int *v = (int *) malloc(sizeof(int));
sleep(1000000000); // time to see memory consumption from htop
return 0;
}
Using top (htop), I can see how much memory is allocated (~4 GiB). Rewriting line 6 into
int *v = (int *) malloc(6*sizeof(int));
I can see that the same amount of memory is being allocated. This changes with malloc(7*sizeof(int)); by such experimentation, I notice that the program always allocates a 32-byte sized block. This becomes very costly because in total I count 32 bytes for the block and 8 bytes for the pointer (If I store them in a vector) = 40 bytes just for one integer, which would otherwise cost only 4 bytes, therefore 10 times higher memory consumption using this dynamic memory allocation. I would like to know why the memory block size is chosen of this size, and why the compiler does not optimize it by reserving a smaller block (just for one integer instead of the one that can accommodate 6 integers). Since I don't have a computer science background and lack the proper terminology, I'm unable to find the correct literature to understand this in more detail. Any recommendation? Thank you.
동일한 양의 메모리가 할당되는 것을 볼 수 있습니다. 이것은 malloc(7*sizeof(int)); 이러한 실험을 통해 나는 프로그램이 항상 32바이트 크기의 블록을 할당한다는 것을 알았습니다. 총 블록에 대해 32바이트, 포인터에 대해 8바이트(벡터에 저장하는 경우) = 하나의 정수에 대해 40바이트를 계산하므로 비용이 매우 많이 듭니다. 그렇지 않으면 비용이 4바이트만 소요되므로 메모리가 10배 더 높습니다. 이 동적 메모리 할당을 사용하여 소비합니다. 메모리 블록 크기가 이 크기로 선택된 이유와 컴파일러가 더 작은 블록(6개의 정수를 수용할 수 있는 블록 대신 하나의 정수에 대해서만)을 예약하여 이를 최적화하지 않는 이유를 알고 싶습니다. 나는 컴퓨터 과학에 대한 배경 지식이 없고 적절한 용어가 부족하기 때문에 이를 더 자세히 이해하는 데 필요한 올바른 문헌을 찾을 수 없습니다. 어떤 추천? 감사합니다.
Answer1
- Memory allocations have to account for alignment requirements of objects that are created in the memory. When you allocate dynamic memory, the implementation doesn't know what type of object you are going to create. Hence, it must align the allocation to the strictest alignment that may be required by any scalar type. Since no dynamic allocation can have lesser alignment, the memory between the allocation and the next aligned address cannot be used.
메모리 할당은 메모리에 생성된 개체의 정렬 요구 사항을 고려해야 합니다. 동적 메모리를 할당할 때 구현에서는 어떤 유형의 객체를 생성할지 알 수 없습니다. 따라서 모든 스칼라 유형에 필요할 수 있는 가장 엄격한 정렬로 할당을 정렬해야 합니다. 동적 할당은 더 낮은 정렬을 가질 수 없으므로 할당과 다음 정렬 주소 사이의 메모리를 사용할 수 없습니다.
Answer2
- In order to be able to deallocate and reuse memory, the memory allocation system must record all allocations in a data structure. This data structure consumes memory itself, in relation to the total number of allocations. With many small allocations, the overhead is relatively larger than with few large allocations.
메모리 할당을 해제하고 재사용하려면 메모리 할당 시스템이 모든 할당을 데이터 구조에 기록해야 합니다. 이 데이터 구조는 총 할당 수와 관련하여 메모리 자체를 소비합니다. 작은 할당이 많으면 큰 할당이 거의 없는 경우보다 오버헤드가 상대적으로 더 큽니다.
Answer3
Memory allocation strategies is a complex area, so it will be be hard to give an answer that covers every scenario. However, typically your library will allocation a large chunk of memory from the operating system and then divide that up into blocks which it will use for allocation requests.
The library will need to keep housekeeping information about the blocks, such as if they are allocated. If the memory you allocate is larger than a single block then the blocks will need to be physically next to each other in memory, and the library will need to know how many blocks are part of the requested allocation (more housekeeping).
Additionally alignment rules mean that the library will been to return a pointer to memory that is correctly aligned. On a 64bit operating system this means that the address will be a multiple of 8, so if you're requesting an allocation less than this then you'll pay a cost.
The library designers will have likely done analysis and worked out what is the optimal block size based on the cost of managing the blocks versus what sizes people typically allocate. It's very rare to just allocate sizeof(int) in the real world, typically it a struct/class or run of memory, at which point the unused portion of the block/blocks not used by your allocation become insignificant.
메모리 할당 전략은 복잡한 영역이므로 모든 시나리오를 포괄하는 답변을 제공하기는 어려울 것입니다. 그러나 일반적으로 라이브러리는 운영 체제에서 큰 메모리 덩어리를 할당한 다음 이를 할당 요청에 사용할 블록으로 나눕니다.
도서관은 할당 여부 등 블록에 대한 관리 정보를 유지해야 합니다. 할당한 메모리가 단일 블록보다 큰 경우 블록은 메모리에서 물리적으로 서로 옆에 있어야 하며 라이브러리는 요청된 할당에 포함된 블록 수를 알아야 합니다(추가 관리).
또한 정렬 규칙은 라이브러리가 올바르게 정렬된 메모리에 대한 포인터를 반환한다는 것을 의미합니다. 64비트 운영 체제에서 이는 주소가 8의 배수가 됨을 의미하므로 이보다 적은 할당을 요청하면 비용을 지불하게 됩니다.
라이브러리 설계자는 블록 관리 비용과 사람들이 일반적으로 할당하는 크기를 기반으로 최적의 블록 크기가 무엇인지 분석하고 계산했을 것입니다. 실제 세계에서 sizeof(int)를 할당하는 경우는 매우 드뭅니다. 일반적으로 구조체/클래스 또는 메모리 실행으로 할당에 사용되지 않는 블록/블록의 사용되지 않은 부분이 중요하지 않게 됩니다.
'코딩 > Memory' 카테고리의 다른 글
#7 [직접구현]small memory object allocator (0) | 2023.11.03 |
---|---|
#6 strategy to allocate/free lots of small objects (0) | 2023.11.03 |
#4 malloc-lab 동적 할당기 구현 (0) | 2023.10.30 |
#3 [직접구현]tcmalloc, malloc 기본 예제 코드 (0) | 2023.10.30 |
#2 mymemory (GitHub) (0) | 2023.10.30 |