C++工作笔记-动态库中的单例类存储方式

背景

最近在改一个老C++大型项目,里面的动态库调用错综复杂,因为要加功能,发现各个动态库调用依靠各自导出的单例类进行,因为需要交互一些数据,特改造了此单例类,但发现没有实现业务效果,通过打印调试等,发现此单例类,构造函数运行了多次。此时就发现问题了。为什么会调用多个函数,并且打印的this指针地址也不同。特意记录了本文章。

感觉工作8年了,才接触到不同dll中创建同一单例类,地址是否一致,这种问题。感觉自己有点low啊。本科期间操作系统或计算机组成稍微学好一点也不至于花了半天时间,才发现这个问题。

结论

每个 DLL/SO 作为独立的加载模块,拥有专属且隔离的全局 / 静态存储区,这是单例实例地址不同的核心原因。

一个运行中的程序(进程)会有一个统一的虚拟地址空间(比如 32 位程序是 4GB),但这个地址空间会被 "分割" 给不同的加载单元(主程序、DLL/SO)。关键在于:

每个 DLL/SO 加载时,会在进程虚拟地址空间中占据独立的一段区域,并且拥有自己的:

代码段(.text):存放函数实现;

数据段(.data):存放已初始化的全局 / 静态变量;

BSS 段(.bss):存放未初始化的全局 / 静态变量。

这些段是模块私有的------ 也就是说,模块 A 的静态变量和模块 B 的同名静态变量,会被分配到进程虚拟地址空间的不同位置,彼此完全隔离。

如在 Windows 下用 VS 调试时:

  1. 主程序的单例实例地址可能是 0x00405000(主程序的静态存储区范围);
  2. DLL1 的单例实例地址可能是 0x10005000(DLL1 的静态存储区范围);
  3. DLL2 的单例实例地址可能是 0x20005000(DLL2 的静态存储区范围);

这些地址分属不同模块的内存区间,本质就是因为每个模块的静态存储区是隔离的。

所以如果是同一个程序常驻动态库中的线程想共享一些数据,还是用最常见的方式把:数据落地、管道、共享内存等都是可以的,看自己业务需求吧。

相关推荐
疯狂打码的少年2 小时前
【数据库技术】关系模型基本概念(关系/属性/元组/键)
java·服务器·数据库·笔记
OPEN-F2 小时前
C++进阶教程:继承与多态
开发语言·c++
luj_17684 小时前
大律师考核应重能力与科技素养
c语言·开发语言·c++·经验分享·算法
有梦想的骇客4 小时前
PyTorch学习笔记
pytorch·笔记·学习
刃神太酷啦5 小时前
Linux 系统 MySQL 完整安装配置教程:从卸载 MariaDB 到优化 my.cnf----《Hello MySQL!》(1)
android·linux·c语言·c++·mysql·leetcode·mariadb
Capricorn19885 小时前
个人知识库接入大模型频现“幻觉引用”?排查 RAG 溯源失效问题,解析知芽构建可信第三大脑的底层架构
大数据·论文阅读·人工智能·笔记·架构·论文笔记
陈年老古董5 小时前
深度学习入门笔记:从神经元到深度神经网络
人工智能·笔记·深度学习·神经网络·学习
leonkay5 小时前
C# 特性(Attribute)——【1】基础讲解
开发语言·青少年编程·面试·c#·.net·个人开发
harmful_sheep5 小时前
java group by常见用法
java·开发语言·python
SKH.6 小时前
Linux软件编程(6)线程间通信
java·开发语言·数据库