当二进制文件运行时,它是否会立即将其整个二进制数据复制到内存中?我可以改变吗?

bxs*_*shi 13 c linux binary

它在执行之前是否将整个二进制文件复制到内存中?我对这个问题很感兴趣,并希望将其改为其他方式.我的意思是,如果二进制文件是100M大(似乎不可能),我可以运行它,而我将它复制到内存中.这有可能吗?

或者你能告诉我如何看待它的运行方式吗?我需要哪些工具?

BRP*_*ock 33

应用程序级程序员的理论模型看起来就是这样.事实上,正常的启动过程(至少在Linux 1.x中,我认为2.x和3.x是优化但相似)是:

  • 内核创建一个进程上下文(或多或少,虚拟机)
  • 在该进程上下文中,它定义了一个虚拟内存映射,该映射从RAM地址映射到可执行文件的开头
  • 假设您是动态链接的(默认/通常),程序头中定义的ld.so程序(例如/lib/ld-linux.so.2)为共享库设置内存映射
  • 内核执行jmp程序的启动例程(对于C程序,就像crtprec80调用它一样main).由于它只设置了映射,并没有实际加载任何页面(*),因此会导致来自CPU内存管理单元的页面错误,这是内核的中断(异常,信号).
  • 内核的Page Fault处理程序将程序的某些部分(包括导致页面错误的部分)加载到RAM中.
  • 当您的程序运行时,如果它正在访问一个没有RAM备份的虚拟地址,那么将发生页面错误并导致内核暂时暂停程序,从光盘加载页面,然后将控制权返回给程序.这一切都发生在"指令之间"并且通常是不可检测的.
  • 当你使用malloc/时new,内核会创建RAM的读写页面(没有光盘后备文件)并将它们添加到你的虚拟地址空间.
  • 如果通过尝试访问在虚拟内存映射中设置的内存位置来引发页面错误,则会收到分段违规信号(SIGSEGV),这通常是致命的.
  • 当系统耗尽物理RAM时,RAM页面会被删除; 如果它们是已经存在于光盘上的东西的只读副本(如可执行文件或共享对象文件),它们只是被取消分配并从其源重新加载; 如果它们是读写的(就像你"使用"创建的那样malloc),它们会被写入(页面文件=交换文件=交换分区=盘上虚拟内存).访问这些"释放"页面会导致另一个页面错误,并且它们会被重新加载.

但是,一般情况下,直到你的进程比可用的RAM大 - 并且数据几乎总是比可执行文件大得多 - 你可以安全地假装你在世界上独自一人而且这种请求分页的东西都没有发生.

所以:实际上,内核在加载程序时已经运行你的程序(如果你从未加入那些代码/引用那些数据,可能永远都不会加载某些页面).

如果您的创业公司特别迟钝,您可以查看prelink系统以优化共享库负载.这减少了ld.so启动时(在exec程序和main被调用之间以及首次调用库例程时)必须执行的工作量.

有时,静态链接可以提高程序的性能,但占用RAM的主要费用 - 因为您的库不是共享的,所以libc除了libc每个其他程序正在使用的共享之外,您还要复制"您的" .这通常仅适用于程序在机器上单独运行的嵌入式系统.

(*)实际上,内核有点聪明,并且通常会预加载一些页面以减少页面错误的数量,但理论是相同的,无论优化如何

  • 我*相信*这些都是由Linux上的`ld.so`处理的,但我不倾向于干涉巫师的事务:-) ...还有很多黑魔法涉及`thunk`操作等等,那个第一次调用库例程时发生... (2认同)

fge*_*fge 6

不,它只将必要的页面加载到内存中.这是需求分页.

我不知道一个可以实时显示的工具,但你可以看看/proc/xxx/maps,xxx你的过程的PID 在哪里.