我在64位Ubuntu系统上使用gcc -Wall -m32 test.c -o test
编译了以下C代码:
#include <stdio.h>
#include <stdlib.h>
int main() {
char * buffer;
buffer = (char*) malloc (1048576);
printf("hi\n");
sleep(20);
return 0;
}
现在,当我运行代码并执行cat /proc/PID/maps
查看进程正在使用的虚拟内存范围时,我会看到以下内容:
08048000-08049000 r-xp 00000000 08:06 3805439 /home/me/test
08049000-0804a000 r--p 00000000 08:06 3805439 /home/me/test
0804a000-0804b000 rw-p 00001000 08:06 3805439 /home/me/test
f7475000-f7577000 rw-p 00000000 00:00 0
f7577000-f7720000 r-xp 00000000 08:06 8002662 /lib/i386-linux-gnu/libc-2.19.so
f7720000-f7721000 ---p 001a9000 08:06 8002662 /lib/i386-linux-gnu/libc-2.19.so
f7721000-f7723000 r--p 001a9000 08:06 8002662 /lib/i386-linux-gnu/libc-2.19.so
f7723000-f7724000 rw-p 001ab000 08:06 8002662 /lib/i386-linux-gnu/libc-2.19.so
f7724000-f7727000 rw-p 00000000 00:00 0
f7746000-f7748000 rw-p 00000000 00:00 0
f7748000-f7749000 r-xp 00000000 00:00 0 [vdso]
f7749000-f7769000 r-xp 00000000 08:06 8002671 /lib/i386-linux-gnu/ld-2.19.so
f7769000-f776a000 r--p 0001f000 08:06 8002671 /lib/i386-linux-gnu/ld-2.19.so
f776a000-f776b000 rw-p 00020000 08:06 8002671 /lib/i386-linux-gnu/ld-2.19.so
ffa60000-ffa81000 rw-p 00000000 00:00 0 [stack]
因此代码区域介于08048000和0804b000之间,那么f7475000-f7577000中缓冲区的堆上有1048576字节。但是在f7577000和f7724000之间,动态链接的libc大约有1758972字节(这几乎就是硬盘上的库的大小)。这是为什么? ld稍微低一点。
为什么系统将整个libc和ld共享对象映射到进程的内存范围?我以为只有一个指向libc的指针,它只在系统范围内加载到内存中?
此外,我绝对不需要整个1758972字节。这里发生了什么?
/lib/i386-linux-gnu/libc-2.19.so只在系统内存一次?
答案 0 :(得分:4)
- 为什么系统将整个libc和ld共享对象映射到进程中?记忆范围?我以为只有一个指向libc的指针,它只在系统范围内加载到内存中?
醇>
它会在系统范围内映射一次,然后将这些页面映射到每个进程中。虚拟内存地址空间。这些页面由每个进程共享(至少是只读部分)
你不能只有一个&#34;指针&#34;因为指针只能引用过程中的事物&#39;自己的地址空间,所以如果一个库不在该地址空间中,你将如何取消引用指针?这也意味着需要说出这个过程&#34;好吧,我想要这个功能,就是在我的地址空间?不,但我有一个指针,所以按照&#34;哪个会复杂得多。相反,操作系统和MMU硬件执行所需的间接和映射,使其显示为每个进程的单个平面地址空间。
- 此外,我绝对不需要整个1758972字节。这里发生了什么?
醇>
由于使用libc.so的每个进程都获得相同的页面,因此只需将整个事物映射一次并共享它,而不是确定每个进程需要哪些特定页面,效率要高得多。
- /lib/i386-linux-gnu/libc-2.19.so只在系统内存一次?
醇>
是的,因为相同的页面被映射到每个进程。
这一切都适用于任何ELF共享库,而不仅仅是libc.so
答案 1 :(得分:2)
您必须能够访问libc.so
中的元素,因此必须这样
映射到你的记忆中。您无法访问未映射的任何内容。
关于它的存在是一次还是多次,你必须解释
完全是你的意思。我将被映射到每个地址空间
使用它的过程(几乎每个过程都是如此)。但是只有
实际上在每个过程中使用的部分实际上是
加载到主内存中。 text
段将直接映射
来自.so
文件,交换区域中没有任何后备存储。 (一世
至少相信。我从来没有真正看过Linux,但这就是
大多数虚拟内存工作方式。这就是为什么库中的代码通常会出现的原因
必须使用-fPIC
进行编译。)
答案 2 :(得分:1)
我以为只会有一个指向加载的libc的指针 只有一次系统内存?
这样的指针会指向什么?指针只能指向内存空间中的某些内容。
但实际上 只在系统范围内存在于内存中。通过内存管理的神奇之处,它可以出现在多个进程的内存中,但实际上只能在内存中运行一次。
仅映射实际使用的libc部分在理论上似乎是可能的,但可能不值得复杂,因为在64位计算机上没有任何好处。它将涉及处理共享库的机制的重要补充。