卸载 c++ 中的静态实例变量插件?
提前致谢。我现在正在用 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 模式下编译时,优化会出现问题。
Thanks in advance. I'm now developing a plugin for a big system in C++. In my plugin I have some static variable. I find that when it is compiled in debug mode on Linux, it works fine without any problem. When it is compiled in RELEASE mode, namely some optimization is done by the compiler, then when I unload the plugin, the static variable is not deleted ( the destructor of the static variable class is never called.) so the memory is never released and next time when I reload the plugin, it causes the main program crash!
Can anybody explain me why the static variable is not destroyed when the plugin is unloaded? NOTE: the static variable is a static instance, not a pointer!
class MySettings
{
public:
static MySettings& Instance() {
static MySettings theSingleton;
return theSingleton;
}
virtual ~MySettings();
}
in the plugin somewhere, it is called like this
....
MySettings &s = MySettings::Instance();
s.xxx();
....
When I compiled and run in debug mode, I printed some information from the destructor, it looks like the instance is destructred properly, when the plugin is unpluged. But when I compile and run in release mode, the destructor is never called when the plugin is unpluged.
I'm not the plugin manager developer, cannot tell too much about it. Thanks a lot for your help!
Here is the piece of code which loaded the plugin libs.
newLib._libHandle = ::dlopen(path_to_the_plugin_lib, RTLD_LAZY | RTLD_GLOBAL);
if(! newLib._libHandle) {
cerr << "dlopen failed for: " << path << " - "
<< ::dlerror();
return "";
I finally get it work. But still don't understand why. Here is what I did:
class MySettings
{
public:
static MySettings& Instance() {
return theSingleton;
}
private:
static MySettings theSingleton;
virtual ~MySettings();
}
MySettings MySettins:theSingleton;
Sinece the application is very big with millions of lines of code. My doubt is that when gcc compiles in RELEASE mode, something goes wrong with the optimization.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我自己从未尝试过这个, 文档 似乎指定静态变量应该在重新加载时“重新初始化”。对我来说,它如何与 C++ 的 pre-
main()
挂钩交互并不明显。您可以尝试理解这一点(检查供应商的文档,或者只是打开二进制文件并查看),但重新设计可能更简单。一些想法:如果可以的话,摆脱你的单身人士。正如评论中提到的,当今业界的共识是,大多数时候,单例模式带来的麻烦多于它的价值——正如您所发现的!公平地说,在 Java 或 Ruby 中不会遇到这个问题,但仍然存在。
如果您使用 gcc 进行编译,则可以为“在
dlopen()
返回之前”和“在dlclose()
被调用之后”注册一些钩子。再次从文档中:我很确定这是 gcc 特定的;如果您不使用 gcc,您的平台可能会提供类似的功能。
如果您做不到这一点,请尝试切换到“首次使用时初始化”单例实现风格。这个想法是在
Instance()
中检测您的MySettings
单例是否已创建,如果尚未创建,则首先创建它。类似于:请注意,此版本的 Instance() 是不是线程安全的;如果你想要的话,你就得惹上麻烦了。另外:
theSingleton
永远不会被删除,因此每次重新加载插件时,您的问题都会泄漏一些内存/文件描述符/任何内容。根据您在MySettings
中保留的内容,以及您希望用户在进程重新启动之间重新加载插件的频率,这可能是可接受的,也可能是不可接受的。希望这有帮助。
I've never tried this myself, the documentation seems to specify that static variables should be "reinitialized" upon reload. It's not at all obvious to me how that interacts with C++'s pre-
main()
hooks. You can try to understand that (check your vendor's documentation, or just open up the binary and look), but it's probably simpler to redesign. Some ideas:If you can, get rid of your singletons. As mentioned in the comments, the industry consensus these days is that most of the time, the singleton pattern is more trouble than it's worth - as you are finding! In fairness, you wouldn't have this problem in Java or Ruby, but still.
If you're compiling with gcc, you may be able to register some hooks for "before
dlopen()
returns" and "afterdlclose()
is called". From the docs again:I'm pretty sure this is gcc-specific; if you're not using gcc, your platform may offer something similar.
If you can't do that, try switching to the "initialize on first use" style of singleton implementation. The idea is to detect in
Instance()
whether yourMySettings
singleton has been created already, and create it first if it hasn't. Something like:Note that this version of
Instance()
is not thread-safe; if you want that you will have to go to some trouble. Also:theSingleton
will never be deleted, so your problem will leak some memory/file descriptors/whatever every time your plugin is reloaded. Depending on what sorts of things you're keeping inMySettings
, and how often you expect users to reload your plugin between process restarts, this may or may not be acceptable.Hope this helps.