进程,动态库,COM机制关系概述

在一个应用程序运行实例中,主程序,以及所调用的模块,库都是在同一个进程中吗?它们的核心工作机制和原理是什么?

在一个应用程序的运行实例中,主程序、它调用的所有模块(如DLL、SO)和库,确实都是在同一个操作系统进程中运行的。这是一个现代操作系统软件架构的核心基础。

你可以把一个进程想象成一个独立的、受保护的“沙盒世界”。操作系统为这个世界分配了虚拟内存、CPU时间片、文件句柄等资源。而主程序、模块、库都是这个沙盒世界里协同工作的“居民”或“功能模块”,它们共享这个世界里的资源,并通过明确的“内部协议”进行沟通。

下图清晰地展示了主程序与动态库如何被加载到同一个进程的虚拟内存空间中协同工作:

一个进程的虚拟地址空间

动态库B模块

动态库A模块

主程序模块

“call printf@plt”

“call自定义函数”

“.text段
库B代码”

“.text段
主程序代码”

“.text段
库A代码”

“.data段
库B全局数据”

“.data段
库A全局数据”

“.data段
主程序全局数据”

“堆
动态分配的内存”

“栈
函数调用、局部变量”

⚙️ 核心工作机制与原理:动态链接与加载

这个过程的核心是“动态链接”,主要由操作系统的动态链接器/加载器(如Linux的ld.so,Windows的NT Loader)在程序启动时或运行时完成。下面我们以Linux/ELF格式为例,拆解其机制。

第一步:启动与加载

当你执行./myapp时:

  1. 操作系统内核首先调用fork()创建一个新进程,然后调用exec()加载myapp
  2. exec()会读取myapp这个ELF可执行文件的头部,发现它有一个INTERP段,指定了动态链接器的路径(如/lib64/ld-linux-x86-64.so.2)。
  3. 内核先将动态链接器本身映射到进程的虚拟内存中,并将控制权交给它。
第二步:依赖分析与映射

动态链接器开始工作:

  1. 它读取myappDYNAMIC段,找出所有依赖的共享库(如libc.so.6,libm.so.6)。
  2. 链接器采用广度优先的策略,将这些库以及它们的依赖库,一个一个地映射到进程的虚拟地址空间中。注意,此时只是建立了磁盘文件到内存区域的映射关系(通过mmap系统调用),并未实际加载全部代码,这就是“按需加载”
  3. 每个库的代码(.text)被映射到只读区域,数据(.data,.bss)被映射到可读写区域。
第三步:符号解析与重定位(关键步骤)

这是让不同模块能互相调用的核心。链接器需要解决所有模块间的符号引用问题。

  • 符号:指函数名、变量名。
  • 定义:符号实际所在的内存地址。
  • 引用:代码中调用该函数或访问该变量的地方。

链接器会建立一个全局的符号表,然后遍历所有模块,进行重定位:

  1. 当主程序myapp的代码中调用了printf,在编译后,这个调用点只是一个“桩”地址(通常通过过程链接表PLT实现)。
  2. 链接器在映射了libc.so.6后,在其导出符号表中找到了printf的真实地址。
  3. 链接器将这个真实地址,填回主程序中对printf引用位置(具体是填入全局偏移表GOT),完成“重定位”。
第四步:初始化与移交控制

所有库映射和符号解析完成后,链接器会依次调用每个共享库的初始化函数。最后,动态链接器将控制权移交到myapp的主函数main(),应用程序开始运行。

💡 实例说明:一个简单的C程序

假设我们有一个简单的C程序hello.c:

#include<stdio.h>#include<math.h>intmain(){doubleval=sin(3.1415926/2);// 调用math库printf("Hello, sin(PI/2)=%f\n",val);// 调用C标准库return0;}

编译:gcc hello.c -lm -o hello

运行时的进程内景

  1. 进程启动:操作系统创建进程,加载/lib64/ld-linux-x86-64.so.2
  2. 加载依赖:动态链接器发现hello依赖libc.so.6printf所在)和libm.so.6sin所在),将它们映射到内存。
  3. 地址绑定
    • 链接器找到sinlibm.so.6代码段中的地址,将该地址填入hello程序中对sin的调用桩。
    • 同理,将printf的地址填入调用桩。
  4. 执行:当CPU执行到main函数中的sin调用指令时,该指令实际上是通过PLT/GOT机制,直接跳转到已加载到本进程内存空间libm.so.6模块的代码区域中执行。printf的调用同理。
  5. 共享:如果此时系统中另一个进程也运行了使用libc.so.6的程序,它们会共享磁盘上同一份libc.so.6文件的代码段物理内存页,但各自拥有独立的数据段副本。这既节省了内存,又保证了进程隔离。

🔗 与调试器原理的联系

这正好能衔接你之前对调试器的理解:因为所有模块都在同一进程空间,所以当调试器(如GDB)通过ptrace附着到该进程时,它就获得了访问这个“沙盒世界”全部内存的权限。它可以:

  • main函数的代码段设断点,也可以在libcprintf函数内部设断点,因为它们在同一个可访问的地址空间。
  • 查看任何模块的全局变量,因为它们都在进程的数据段内。
  • 获得完整的调用栈,这个栈上可能混合了来自主程序、libmlibc等多个模块的帧。

总的来说,主程序、模块、库在同一个进程中协作,是现代软件“分而治之”与“代码复用”的基石。其核心机制是:操作系统通过动态链接器,将独立的代码模块映射到同一个进程的虚拟地址空间,并通过重定位技术解决它们之间的相互引用问题,最终形成一个可以统一调度和执行的合作整体。

应用程序调用com组件时,是否也是在同一个进程中呢?

经典的COM组件调用不在同一个进程中。

这背后的核心理念是稳定性、安全性与隔离性。当组件运行在独立进程中时,它的崩溃、泄漏或错误,不会直接导致调用它的主应用程序(如Word、Excel)崩溃。

为了更清晰地对比,我们可以将这两种模型与两种不同的“合作模式”进行类比:

渲染错误:Mermaid 渲染失败: Parse error on line 2: ...subgraph DLL[“动态链接库 (DLL) 模式”] d -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

这两种模型在工作机制和目标上有着根本区别:

📌 动态链接库 vs. COM组件:核心区别

特性动态链接库COM组件 (跨进程)
核心目标代码复用与高效执行功能隔离与系统稳定
加载方式映射到主程序进程的地址空间,成为其一部分。运行在独立的进程中,拥有自己的地址空间。
通信机制直接函数调用,通过CPU指令跳转,无额外开销。进程间通信,需要复杂的参数封送
错误影响DLL中的错误(如内存越界)会直接破坏主进程,导致一起崩溃组件进程崩溃,通常不会导致客户端进程崩溃。
安全边界无隔离,DLL拥有主进程的所有权限。有进程隔离,可通过配置在不同权限的账户下运行。
升级维护需要替换DLL文件,可能影响所有使用它的程序。可独立升级、重启组件服务,不影响客户端。

⚙️ COM跨进程调用的核心机制:RPC与封送

COM实现跨进程协作的魔法,主要依靠以下核心技术:

  1. 代理与存根

    • 代理:存在于客户端进程中。它看起来和感觉上就像本地的COM对象,实现了相同的接口。当你调用其方法时,它并不执行实际功能,而是将参数打包,通过IPC发送给组件进程。
    • 存根:存在于组件进程中。它接收来自代理的IPC消息,解包参数,然后调用真实的COM对象上的方法。拿到返回值后,再打包发回给代理。
  2. 封送
    这是跨进程通信中最复杂的一步。因为两个进程内存空间完全独立,指针、结构体等内存地址在对方进程中是无效的。

    • 封送:代理需要将方法参数(可能是一个复杂的结构体、字符串甚至接口指针)序列化成一个与进程无关的字节流。
    • 解封:存根在组件进程中接收这个字节流,反序列化,在本进程的地址空间中重建出一份完全相同的参数副本,然后进行调用。
  3. 调度
    Windows的RPC运行时库负责处理底层的进程间通信(通常基于LRPCALPC),包括建立连接、传输数据、同步和异常处理。

📝 实例详解:Word调用拼写检查COM组件

假设你在Microsoft Word中点击了“拼写和语法检查”:

  1. Word(客户端进程)通过COM系统API请求一个拼写检查组件。
  2. COM系统查看该组件的注册信息,发现它是一个进程外服务器(通常是一个独立的EXE,或由DLLHOST托管)。
  3. COM系统启动或连接到这个组件进程,并在Word进程中为该组件创建一个代理对象。
  4. 你输入文本并开始检查。Word调用代理的CheckText方法。
  5. 代理将文本字符串、语言设置等参数封送成一个数据包。
  6. 数据包通过RPC从Word进程传输到拼写检查组件进程。
  7. 组件进程中的存根接收数据包,解封出文本和设置。
  8. 存根调用真实拼写检查引擎CheckText方法。
  9. 引擎返回错误列表。存根封送这个结果列表,通过RPC传回Word进程。
  10. Word进程中的代理解封结果,并将其作为方法返回值交给Word的代码。Word随后在界面上用红线下划出错误单词。

整个过程对Word的开发者和用户而言,几乎感觉不到进程边界的存在,仿佛就在调用一个本地函数。但底层的进程隔离保证了如果拼写检查引擎遇到致命错误而崩溃,Word本身可以捕获到这个错误,并可能只是提示“拼写检查服务不可用”,而不会导致你正在编辑的文档丢失。

💎 总结:两种哲学的选择

  • 选择DLL(同进程):当你追求极致的性能,且模块与主程序高度信任、共生共死时(如图形引擎、数学库)。
  • 选择进程外COM:当你需要隔离风险独立升级跨安全边界,或构建分布式系统时(如Office插件、杀毒软件、数据库查询处理器)。

所以,正是出于对系统稳定性和架构灵活性的更高追求,COM才选择了更复杂、开销更大的跨进程调用模型。这也是Windows从OLE、DCOM发展到今天的COM+和Windows Runtime的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1098118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RAG学习笔记 检索优化

检索增强技术进阶学习笔记 混合检索 (Hybrid Search) 核心思想:结合稀疏向量与密集向量,利用关键词精确匹配与语义理解的双重优势,克服单一检索的局限性。 技术原理:稀疏向量 (Sparse Vectors):表示:基于词频统计…

【毕业设计】基于SpringBoot的汽车配件仓储管理系统设计与实现(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

降AI率不靠硬改,前五工具更省事

又到毕业季&#xff0c;毕业论文除了查重外&#xff0c;真的别忘记查ai率。 今天就告诉大家高重复率以及高ai率应该如何快速降低&#xff01;实测全网产品&#xff0c;无广&#xff01;&#xff01; 如果这篇整理能帮你少走点弯路&#xff0c;那就值了。 1、嘎嘎降AI 官网&…

Kingbase-KEMCC配置集群监控纳管ES以及外部备份使用对象存储

之前有幸测试过的KEMCC&#xff0c; 有了新版本&#xff0c;有幸拿到内测版本&#xff0c;进行提前体验测试。 这里就不过多的介绍KEMCC和安装方式了&#xff0c;可以看这篇文章&#xff1a; Kingbase-金仓企业级统一管控平台KEMCC安装初体验 关于KEMCC非云初始化以及实例管…

Java计算机毕设之基于SpringBoot的汽车配件仓储管理系统设计与实现配件信息、供应商、库存、采购、销售(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

读书笔记7-12.4

第七章主要讲的是项目启动前必须搞定的那些“大问题”,就像盖房子前得先打好地基一样。作者认为,如果这些问题没想清楚,项目从一开始就注定要失败。这一章的核心思想是,在动手写代码之前,得先搞清楚用户到底要什么…

【基于LLaMA-Factory通义千问】大模型微调全流程技术解析

文章目录 目录一、前置认知&#xff1a;核心基础信息与硬件适配1.1 核心基础属性1.2 核心技术-硬件-数据关联 二、核心环节一&#xff1a;4万条领域数据预处理与格式转换2.1 数据预处理2.2 格式转换 三、核心环节二&#xff1a;LoRA参数调优&#xff08;32B模型&#xff09;与2…

Java毕设选题推荐:基于SpringBoot+Vue的汽车配件仓储管理系统管理系统设计基于SpringBoot的汽车配件仓储管理系统设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

UDP-N-叠氮乙酰葡萄糖胺二钠盐:糖蛋白化学生物学研究的关键工具

UDP-N-2-[(叠氮基乙酰基)氨基]-2-脱氧-D-葡萄糖二钠盐&#xff08;UDP-N-azidoacetylglucosamine disodium salt&#xff09;是一类经过化学生物学改造的糖核苷酸。作为代谢糖工程的核心试剂&#xff0c;它使得研究人员能够对细胞内的糖基化过程进行特异性标记与调控&#xff0…

从Java全栈开发到云原生实践:一次真实面试的深度记录

从Java全栈开发到云原生实践&#xff1a;一次真实面试的深度记录 面试官与应聘者的初次接触 面试官&#xff1a;你好&#xff0c;我是负责技术面试的工程师&#xff0c;今天主要想了解一下你的技术背景和项目经验。可以先简单介绍一下你自己吗&#xff1f; 应聘者&#xff1a;好…

AI原生语义搜索:从理论到实践的全面解析

AI原生语义搜索&#xff1a;从理论到实践的全面解析 关键词&#xff1a;AI原生语义搜索、自然语言处理&#xff08;NLP&#xff09;、向量检索&#xff08;Vector Search&#xff09;、预训练模型、语义理解、Embedding、多模态搜索 摘要&#xff1a;本文从“用户想找‘苹果’却…

P5607 [Ynoi2013] 无力回天 NOI2017 题解

一道很好的题,如果做法不当(像我)可能需要一些卡常。 Part 1. bitset 20tps 插入?并集? \(1e5\) ?显然可以用 \(bitset\) 维护:每次修改把第 \(x\) 个 \(bitset\) 中的第 \(y\) 位修改成1 每次查询将 \(x1\) 和…

【计算机毕业设计案例】基于SpringBoot的学校图书管理系统设计与实现图书管理、借阅记录、审核借阅、图书续借、审核续借、确认归还(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

AI+SQL生成ER图

AISQL生成ER图&#xff1a;计算机专业作业/毕设高效通关指南 工具地址&#xff1a;https://draw.anqstar.com/template 一、技术背景与问题引入&#xff1a;ER图绘制&#xff0c;为何成为作业/毕设拦路虎&#xff1f; 1.1 计算机专业课程中的ER图刚需场景 对于计算机专业的同…

P5607 [Ynoi2013] 无力回天 NOI2017 题解

一道很好的题,如果做法不当(像我)可能需要一些卡常。 Part 1. bitset 20tps 插入?并集? \(1e5\) ?显然可以用 \(bitset\) 维护:每次修改把第 \(x\) 个 \(bitset\) 中的第 \(y\) 位修改成1 每次查询将 \(x1\) 和…

计算机Java毕设实战-基于SpringBoot的房屋租赁系统的设计与实现基于Springboot的房屋租赁网站的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

CSDN年度技术趋势预测

CSDN技术趋势预测概览CSDN作为国内知名的开发者社区&#xff0c;每年会基于行业动态、用户行为及专家分析发布技术趋势预测。以下是综合多方信息整理的2023年重点关注领域&#xff1a;人工智能与机器学习生成式AI&#xff08;如ChatGPT、Stable Diffusion&#xff09;持续爆发&…

官网-城乡居民医疗保险报销政策

官网:2023年宿迁市基本医疗保险待遇政策一览表-宿迁市人民政府 一、居民医保门诊报销政策 (一)普通门诊 就诊机构 起付线(元) 报销比例 待遇范围 单日处方限额 年度限额(元) 乡镇一级医院、村居卫生机构 0 55% 合规药费 乡镇一级医院100元;村居卫生机构30元 300 城区…

去掉手写字上面的表格线

截取手写字的时候,有些人的字与表格重叠了,把表格也截出来了,需要去掉。 方法:右击用画图打开,直接点橡皮擦,擦掉就可以了