卸载c++插件中的静态实例变量

unload a static instance variable in c++ plugin?

本文关键字:静态 实例 变量 c++ 插件 卸载      更新时间:2023-10-16

提前感谢。我现在正在用c++为一个大系统开发一个插件。在我的插件我有一些静态变量。我发现当它在Linux上以调试模式编译时,它工作得很好,没有任何问题。当它在RELEASE模式下编译时,即编译器做了一些优化,然后当我卸载插件时,静态变量不会被删除(静态变量类的析构函数永远不会被调用),所以内存永远不会被释放,下次当我重新加载插件时,它会导致主程序崩溃!

谁能解释一下为什么静态变量不销毁插件卸载时?注意:静态变量是静态实例,而不是指针!

class MySettings
{
   public:
      static MySettings& Instance() {
         static MySettings theSingleton;
         return theSingleton;
      }
      virtual ~MySettings();
}

在插件的某个地方,它像这样被调用

....
MySettings &s = MySettings::Instance();
s.xxx();
....

当我在调试模式下编译和运行时,我从析构函数中打印了一些信息,当插件被拔掉时,看起来实例被正确地析构了。但是当我在发布模式下编译和运行时,当插件被拔下时,永远不会调用析构函数。我不是插件管理器的开发者,不能说太多。非常感谢你的帮助!

下面是加载插件库的一段代码。

newLib._libHandle = ::dlopen(path_to_the_plugin_lib, RTLD_LAZY | RTLD_GLOBAL);
if(! newLib._libHandle) {
  cerr << "dlopen failed for: " << path << " - "
             << ::dlerror();
  return "";

我终于让它工作了。但还是不明白为什么。以下是我所做的:

class MySettings
{
   public:
      static MySettings& Instance() {
         return theSingleton;
      }
   private:
      static MySettings theSingleton;
      virtual ~MySettings();
}
MySettings MySettins:theSingleton;

因为应用程序非常大,有数百万行代码。我的疑问是,当gcc以RELEASE模式编译时,优化出了问题。

我自己从来没有尝试过,文档似乎指定静态变量应该在重新加载时"重新初始化"。对我来说,它是如何与c++的pre- main()钩子相互作用的,一点也不明显。您可以尝试理解这一点(检查供应商的文档,或者只是打开二进制文件并查看),但重新设计可能更简单。一些想法:

如果可以的话,去掉你的单例。正如评论中提到的,目前业界的共识是,大多数时候,单例模式带来的麻烦比它的价值要多——正如您所发现的那样!公平地说,在Java或Ruby中不会有这个问题,但是仍然。

如果你用gcc编译,你可以为"dlopen()返回之前"answers"dlclose()被调用之后"注册一些钩子。再次从文档:

...libraries should export routines using the __attribute__((constructor)) and __attribute__((destructor)) function attributes. See the gcc info pages for information on these. Constructor routines are executed before dlopen() returns, and destructor routines are executed before dlclose() returns."

我很确定这是gcc特有的;如果您不使用gcc,您的平台可能提供类似的功能。

如果你不能这样做,试着切换到单例实现的"首次使用初始化"风格。这个想法是在Instance()中检测您的MySettings单例是否已经创建,如果没有,则首先创建它。比如:

static MySettings* theSingleton = NULL;
if(theSingleton == NULL)
  theSingleton = new MySettings();
return *theSingleton;

注意这个版本的Instance()不是线程安全的;如果你想那样做,你就得费点劲。另外:theSingleton将永远不会被删除,所以你的问题会泄漏一些内存/文件描述符/无论你的插件每次重新加载。这取决于你在MySettings中保留的东西,以及你希望用户在进程重启之间重新加载插件的频率,这可能是可接受的,也可能是不可接受的。