为什么 malloc 在我达到某个阈值之前不分配内存?
Why malloc doesn't allocate memory until I hit a certain threshold?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
size_t sz = atol(argv[1]);
char *arr = malloc(sz);
sleep(10);
}
我编译了这段代码并尝试运行它,使用pmap
查看程序的内存映射。
当我使用像 1024000
这样的大数字时,我得到这样的映射:
3901: ./alloc_program 1024000
0000560192f43000 4K r---- alloc_program
0000560192f44000 4K r-x-- alloc_program
0000560192f45000 4K r---- alloc_program
0000560192f46000 4K r---- alloc_program
0000560192f47000 4K rw--- alloc_program
0000560192fac000 132K rw--- [ anon ]
00007f75b69e9000 1004K rw--- [ anon ] <---- I believe this is the allocated memory
00007f75b6ae4000 148K r---- libc-2.31.so
00007f75b6b09000 1504K r-x-- libc-2.31.so
00007f75b6c81000 296K r---- libc-2.31.so
00007f75b6ccb000 4K ----- libc-2.31.so
00007f75b6ccc000 12K r---- libc-2.31.so
00007f75b6ccf000 12K rw--- libc-2.31.so
00007f75b6cd2000 24K rw--- [ anon ]
00007f75b6ce7000 4K r---- ld-2.31.so
00007f75b6ce8000 140K r-x-- ld-2.31.so
00007f75b6d0b000 32K r---- ld-2.31.so
00007f75b6d14000 4K r---- ld-2.31.so
00007f75b6d15000 4K rw--- ld-2.31.so
00007f75b6d16000 4K rw--- [ anon ]
00007ffe2b26e000 132K rw--- [ stack ]
00007ffe2b318000 12K r---- [ anon ]
00007ffe2b31b000 4K r-x-- [ anon ]
ffffffffff600000 4K --x-- [ anon ]
total 3496K
我想标记的那一行是malloc分配的内存(也许我错了)。
但是当我使用像 10240
这样的小数字时,我没有看到任何东西被分配:
3879: ./alloc_program 10240
000055e428e26000 4K r---- alloc_program
000055e428e27000 4K r-x-- alloc_program
000055e428e28000 4K r---- alloc_program
000055e428e29000 4K r---- alloc_program
000055e428e2a000 4K rw--- alloc_program
000055e42a257000 132K rw--- [ anon ]
00007f102332c000 148K r---- libc-2.31.so
00007f1023351000 1504K r-x-- libc-2.31.so
00007f10234c9000 296K r---- libc-2.31.so
00007f1023513000 4K ----- libc-2.31.so
00007f1023514000 12K r---- libc-2.31.so
00007f1023517000 12K rw--- libc-2.31.so
00007f102351a000 24K rw--- [ anon ]
00007f102352f000 4K r---- ld-2.31.so
00007f1023530000 140K r-x-- ld-2.31.so
00007f1023553000 32K r---- ld-2.31.so
00007f102355c000 4K r---- ld-2.31.so
00007f102355d000 4K rw--- ld-2.31.so
00007f102355e000 4K rw--- [ anon ]
00007fff1d513000 132K rw--- [ stack ]
00007fff1d570000 12K r---- [ anon ]
00007fff1d573000 4K r-x-- [ anon ]
ffffffffff600000 4K --x-- [ anon ]
total 2492K
1 - 内存比较小为什么不分配?
2 - 为什么分配的内存大小不完全一样?在第一个 运行 中,它显示大小为 1004KB
而我只分配了 1000KB
.
您在 pmap
输出中看到的几乎可以肯定是 addition malloc
arena 需要以满足更大的请求,而不是任何 单个请求.
arena 是从中分发分配的内存池,它很有可能从一定大小开始,并且仅按需扩展。
例如,如果初始arena是1000K,任何没有耗尽的分配都不需要获得额外的arenaspace。如果您 耗尽 space,进程将尝试从底层环境请求更多的 arena 以满足额外的需求。
至于为什么尺寸不是您要求的尺寸,有(至少)两个可能的原因。首先,arena 不仅仅是为您的目的分配的内存,它还包含控制信息,以便可以正确管理内存(大小、校验和、指针、空闲列表等)。
其次,malloc
可能会过度分配,因为预计这不会是耗尽当前竞技场的最后一个请求。一些内存分配策略甚至在请求更多时 双倍 当前 arena 大小,以分摊这样做的成本。
1 - Why it doesn't allocate when the memory size is relatively small?
函数 malloc
的任务是在应用程序需要时为应用程序提供内存。从理论上讲,malloc
可以像您建议的那样,将所有内存分配请求转发给操作系统的 kernel,以便它仅充当内核内存分配器的包装器。但是,这有以下缺点:
- 内核一次只提供大量内存,至少一个 page 内存,根据操作系统的配置,通常至少 4096 字节。因此,如果一个应用程序只要求10个字节的内存,就会浪费很多内存。
- System calls 在 CPU 性能方面很昂贵。
出于这些原因,malloc
不将内存分配请求直接转发给内核,而是充当应用程序内存分配请求与内核之间的中介,效率更高。它从内核请求大量内存,以便它可以满足应用程序的许多较小的内存分配请求。
因此,只有在一次请求大量内存时,才会malloc
将该内存分配请求转发给内核。
2 - Why the allocated memory size is not exactly the same? In the first run, it shows that the size is 1004KB
while I've only allocated 1000KB
.
malloc
分配器必须跟踪它授予应用程序的所有内存分配,还必须跟踪内核授予它的所有内存分配。要存储此信息,它需要一些额外的内存 space。这个额外的 space 称为“开销”。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
size_t sz = atol(argv[1]);
char *arr = malloc(sz);
sleep(10);
}
我编译了这段代码并尝试运行它,使用pmap
查看程序的内存映射。
当我使用像 1024000
这样的大数字时,我得到这样的映射:
3901: ./alloc_program 1024000
0000560192f43000 4K r---- alloc_program
0000560192f44000 4K r-x-- alloc_program
0000560192f45000 4K r---- alloc_program
0000560192f46000 4K r---- alloc_program
0000560192f47000 4K rw--- alloc_program
0000560192fac000 132K rw--- [ anon ]
00007f75b69e9000 1004K rw--- [ anon ] <---- I believe this is the allocated memory
00007f75b6ae4000 148K r---- libc-2.31.so
00007f75b6b09000 1504K r-x-- libc-2.31.so
00007f75b6c81000 296K r---- libc-2.31.so
00007f75b6ccb000 4K ----- libc-2.31.so
00007f75b6ccc000 12K r---- libc-2.31.so
00007f75b6ccf000 12K rw--- libc-2.31.so
00007f75b6cd2000 24K rw--- [ anon ]
00007f75b6ce7000 4K r---- ld-2.31.so
00007f75b6ce8000 140K r-x-- ld-2.31.so
00007f75b6d0b000 32K r---- ld-2.31.so
00007f75b6d14000 4K r---- ld-2.31.so
00007f75b6d15000 4K rw--- ld-2.31.so
00007f75b6d16000 4K rw--- [ anon ]
00007ffe2b26e000 132K rw--- [ stack ]
00007ffe2b318000 12K r---- [ anon ]
00007ffe2b31b000 4K r-x-- [ anon ]
ffffffffff600000 4K --x-- [ anon ]
total 3496K
我想标记的那一行是malloc分配的内存(也许我错了)。
但是当我使用像 10240
这样的小数字时,我没有看到任何东西被分配:
3879: ./alloc_program 10240
000055e428e26000 4K r---- alloc_program
000055e428e27000 4K r-x-- alloc_program
000055e428e28000 4K r---- alloc_program
000055e428e29000 4K r---- alloc_program
000055e428e2a000 4K rw--- alloc_program
000055e42a257000 132K rw--- [ anon ]
00007f102332c000 148K r---- libc-2.31.so
00007f1023351000 1504K r-x-- libc-2.31.so
00007f10234c9000 296K r---- libc-2.31.so
00007f1023513000 4K ----- libc-2.31.so
00007f1023514000 12K r---- libc-2.31.so
00007f1023517000 12K rw--- libc-2.31.so
00007f102351a000 24K rw--- [ anon ]
00007f102352f000 4K r---- ld-2.31.so
00007f1023530000 140K r-x-- ld-2.31.so
00007f1023553000 32K r---- ld-2.31.so
00007f102355c000 4K r---- ld-2.31.so
00007f102355d000 4K rw--- ld-2.31.so
00007f102355e000 4K rw--- [ anon ]
00007fff1d513000 132K rw--- [ stack ]
00007fff1d570000 12K r---- [ anon ]
00007fff1d573000 4K r-x-- [ anon ]
ffffffffff600000 4K --x-- [ anon ]
total 2492K
1 - 内存比较小为什么不分配?
2 - 为什么分配的内存大小不完全一样?在第一个 运行 中,它显示大小为 1004KB
而我只分配了 1000KB
.
您在 pmap
输出中看到的几乎可以肯定是 addition malloc
arena 需要以满足更大的请求,而不是任何 单个请求.
arena 是从中分发分配的内存池,它很有可能从一定大小开始,并且仅按需扩展。
例如,如果初始arena是1000K,任何没有耗尽的分配都不需要获得额外的arenaspace。如果您 耗尽 space,进程将尝试从底层环境请求更多的 arena 以满足额外的需求。
至于为什么尺寸不是您要求的尺寸,有(至少)两个可能的原因。首先,arena 不仅仅是为您的目的分配的内存,它还包含控制信息,以便可以正确管理内存(大小、校验和、指针、空闲列表等)。
其次,malloc
可能会过度分配,因为预计这不会是耗尽当前竞技场的最后一个请求。一些内存分配策略甚至在请求更多时 双倍 当前 arena 大小,以分摊这样做的成本。
1 - Why it doesn't allocate when the memory size is relatively small?
函数 malloc
的任务是在应用程序需要时为应用程序提供内存。从理论上讲,malloc
可以像您建议的那样,将所有内存分配请求转发给操作系统的 kernel,以便它仅充当内核内存分配器的包装器。但是,这有以下缺点:
- 内核一次只提供大量内存,至少一个 page 内存,根据操作系统的配置,通常至少 4096 字节。因此,如果一个应用程序只要求10个字节的内存,就会浪费很多内存。
- System calls 在 CPU 性能方面很昂贵。
出于这些原因,malloc
不将内存分配请求直接转发给内核,而是充当应用程序内存分配请求与内核之间的中介,效率更高。它从内核请求大量内存,以便它可以满足应用程序的许多较小的内存分配请求。
因此,只有在一次请求大量内存时,才会malloc
将该内存分配请求转发给内核。
2 - Why the allocated memory size is not exactly the same? In the first run, it shows that the size is
1004KB
while I've only allocated1000KB
.
malloc
分配器必须跟踪它授予应用程序的所有内存分配,还必须跟踪内核授予它的所有内存分配。要存储此信息,它需要一些额外的内存 space。这个额外的 space 称为“开销”。