它在执行之前是否将整个二进制文件复制到内存中?我对这个问题很感兴趣,并希望将其改为其他方式。我的意思是,如果二进制文件是100M大(似乎不可能),我可以运行它,而我将它复制到内存中。这有可能吗?
或者你能告诉我如何看待它的运行方式吗?我需要哪些工具?
答案 0 :(得分:32)
应用程序级程序员的理论模型看起来就是这样。事实上,正常的启动过程(至少在Linux 1.x中,我相信2.x和3.x是优化但相似)是:
ld.so
程序
(例如/lib/ld-linux.so.2
)在程序的头文件中定义,为共享库设置内存映射jmp
(对于C程序,那就是
类似crtprec80
的内容,调用main
)。由于它只设置了映射,并没有实际加载任何页面(*),因此会导致来自CPU内存管理单元的页面错误,这是内核的中断(异常,信号)。malloc
/ new
时,内核会创建RAM的读写页面(没有光盘后备文件),并将它们添加到您的虚拟地址空间。malloc
“创建”的那样),它们会被写入(页面文件=交换文件=交换分区=盘上虚拟内存)。访问这些“已释放”页面会导致另一个页面错误,并且它们会被重新加载。但是,一般情况下,直到你的进程大于可用内存 - 并且数据几乎总是比可执行文件大得多 - 你可以安全地假装你在这个世界中独处,并且没有发生这种请求分页的事情。 / p>
所以:实际上,内核已经 在加载程序时运行你的程序(如果你从未加载过某些页面,可能永远不会加载那些代码/引用那些数据)。
如果您的创业公司特别迟钝,您可以查看prelink
系统以优化共享库负载。这减少了ld.so
在启动时(在程序的exec
和main
被调用之间以及首次调用库例程时)必须执行的工作量。
有时,静态链接可以提高程序的性能,但是占用RAM的主要成本 - 因为您的库不是共享的,除了共享{{1}之外,您还复制了“libc
”例如,每个其他程序正在使用的。这通常仅适用于程序在机器上运行或多或少运行的嵌入式系统。
(*)实际上,内核有点聪明,通常会预加载一些页面 减少页面错误的数量,但理论是相同的,无论如何 优化
答案 1 :(得分:6)
不,它只将必要的页面加载到内存中。这是请求分页。
我不知道哪种工具可以实时显示,但您可以查看/proc/xxx/maps
,其中xxx
是您的流程的PID。
答案 2 :(得分:2)
当你问一个有效的问题时,我认为你不必担心这个问题。首先,100M的二进制文件并非不可能。其次,系统加载器会将所需的页面从ELF(可执行文件和可链接格式)加载到内存中,并执行各种重定位等,以便在必要时使其工作。它还将以相同的方式加载其所有必需的共享库依赖项。但是,这不是一个非常耗时的过程,并且不需要进行优化。可以说,任何“优化”都会产生很大的开销,以确保它不会尝试使用未在适当时候加载的东西,并且可能更少效率。
如果你很好奇被映射的内容,正如fge所说,你可以检查/ proc / pid / maps。如果您想了解程序的加载方式,可以尝试使用strace
运行程序,例如:
strace ls
它非常冗长,但它应该让你对mmap()调用等有所了解。