【问题标题】:Lifespan of a static member variable declared and initialized in a dynamically loaded DLL在动态加载的 DLL 中声明和初始化的静态成员变量的寿命
【发布时间】:2020-04-29 03:04:18
【问题描述】:

请考虑以下代码示例。我的问题是:Foo::bar 存储在内存中的什么位置?是存放在main.cpp编译成的程序的静态存储中吗?如果是这样,当 myDll.so 被卸载时会发生什么?

//myDll.hpp

//class definitions
class Bar
{
  public:
    Bar() = default;
};

class Foo
{
  public:
    static Bar bar;
};

//declaring free function to be exported
extern "C" Bar* getBar();

//myDll.cpp
#include "myDll.hpp"

//initializing static member variable
Bar Foo::bar;

//definition of exported function
Bar* getBar()
{
  return &(Foo::bar);  
}

假设 myDll.cpp 像这样被制作成 myDll.so: g++ -shared -fPIC -o myDll.so myDll.cpp,动态加载如下:

//main.cpp
void* handle = dlopen( "/path/to/dll/myDll.so", RTLD_NOW);
// do stuff with handle...
dlclose( handle ); 

调用 dlclose() 时会发生什么? Foo::bar 会立即超出范围吗?

【问题讨论】:

    标签: c++ dll static dynamic-loading


    【解决方案1】:

    是的。 Foo::bar 存在于myDll.so 的静态存储部分(“.data”段)中,在dlclose 之后将被取消映射。

    我能想到两个例外:

    • 卸载 DLL 不需要 C 库。一些 C 库(例如,musl)明确记录它们无操作 dlclose()
    • dlopen/dlclose 被引用计数。如果您在同一个库上调用了两次dlopen,则第一次调用dlopen 将不会卸载该库。

    【讨论】:

    • 你是说myDll.so 和主程序(main.cpp 编译成的程序)有单独的静态存储部分,对吧?如果是这样,我想知道他们是否也有单独的堆栈和堆?
    • @megamonium 堆栈属于线程,不属于 .so 或 DLL 或 EXE。 C 运行时可以在 .so 中有一个单独的内存堆,具体取决于 .so 的链接方式。
    • 没错,每个库都有自己的静态变量部分。然而,“堆栈”(最初由内核设置)和“堆”(使用 brk() 扩展)不共享。作为实验,您可以在 dlopen 之前、dlclose 之前和 dlclose 之后对 PID 运行 pmap。您将看到为 dll 创建了“读取/不执行”映射,然后在 dlclose 后将其删除。这是变量所在的地址
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多