linux - Linux共享库加载并与其他进程共享代码
问题描述
假设我有一个a.so
由我的可执行文件首次加载的共享库。我的理解是,到 VMA 的中间,共享库文本部分被映射。我有两个问题;
(1) ld.so 是否会将此共享内存文本节页面加载到物理内存,然后映射到该进程的 VMA?
(2) 假设启动了第二个使用相同共享库的可执行文件a.so
。ld.so 是否会识别该共享库已加载到物理内存中?如何理解这一点?
解决方案
准确地说,ld.so
保留物理内存或管理或选择虚拟内存和物理内存之间的映射不是他们的工作,而是内核的工作。加载共享库时ld.so
,它通过mmap
系统调用完成,内核分配所需的物理内存(1)并在库文件和物理内存之间创建虚拟映射。然后返回的mmap
是映射库的虚拟基地址,然后动态加载程序将使用该基地址作为对该库函数的调用的基础。
是否
ld.so
要确定此共享库已加载到物理内存?如何理解这一点?
不是ld.so
,而是要识别它的内核。这是一个复杂的过程,但为了简单起见,内核会跟踪哪个文件映射到哪里,并且可以检测何时再次请求映射已经映射的文件,尽可能避免物理内存分配。
如果同一个文件(即具有相同路径的文件)被多次映射,内核将查看现有的映射,如果可能,它会重用相同的物理页以避免浪费内存。所以理想情况下,如果一个共享库被多次加载,它只能被物理分配一次。
但在实践中并不是那么简单。由于也可以写入内存,因此这种物理页面的“共享”显然只有在需要共享的页面与文件的原始内容没有变化时才会发生(否则映射同一文件或库的不同进程会相互干扰其他)。这对于代码部分 ( .text
) 基本上总是正确的,因为它们通常是只读的,对于其他类似的部分(如只读数据)也是如此。如果未修改 RW 部分,也可能发生这种情况(2)。所以简而言之,.text
已经加载的库的段通常只分配到物理内存一次。
(1) 实际上,内核首先创建映射,然后只有当进程试图通过映射读取或写入它时才分配物理内存。这可以防止在不需要时浪费内存。
(2) 这种共享物理内存的技术是通过写时复制机制管理的,内核最初映射“干净”页面,并在写入时将它们标记为“脏”,并根据需要复制它们。
推荐阅读
- python - 如何使用 Python 从 sqlite3 显示 BLOB 对象(图像)
- html - 红色背景的跨度不可见?
- java - ¿ 我可以在 Optapplaner 求解器配置中调整什么来选择这个动作?
- reactjs - 如何在 axios 中附加 JSON Web 令牌
- python - 如何从熊猫列表中获取价值?
- c++ - 将数据从 c++ 文件连续发送到 Python 脚本以进行进一步处理
- c++ - 如何使用多线程生成事件以及如何在 C++ 中同步它们?
- bootstrap-4 - 无法让引导网格与 shopify 购买按钮一起使用
- java - 如何将 Alfresco 查询结果集限制为仅前 N 行
- asp.net-core - 调用发布到服务器的页面后,ASP.Net Core Web Api 不起作用