一、dll间调用顺序不明朗,导致资源释放错乱
修正【正常关服】时资源回收异常的问题。
项目大量使用dll进行组件化设计,跨dll 间资源的不恰当传递和回收方式 都会引起问题。在 GameServer 关服时就出现了资源回收异常,表现为:
在 NFGameServerNet_ServerPlugin.dll 创建了一个【资源R】 供 NFUrlPlugin.dll 使用,
应该在关服时 由 NFGameServerNet_ServerPlugin.dll 回收,但是NFGameServerNet_ServerPlugin.dll 先进行卸载, NFUrlPlugin.dll 卸载时无法找到 【资源R】的正确回收器,进而会出现 Access Violation at Address(地址访问冲突)。
按照如下的dll配置循序:
配置的dll加载与卸载顺序PluginNameMap NFCPluginManager::mPluginNameMap;
PluginNameMap NFCPluginManager::mPluginNameMapTwo;
虽然原有代码有两个类成员的"意图可能"是为了控制dll的加载卸载顺序的,但是没有写对(在不明朗原有代码意图的情况下,尽量少修改原有的代码,我用新的代码实现了)。
二、dll的对象管理
这个比较基础,也是接触dll 的程序员都需要掌握的,例如通过C语言的 extern, 还是C++的 dllimport/dllexport 方式;如果暴露类可能需要使用面向接口编程,类内部有成员变量,也要考虑其可暴露性。STL作为参数传递时,要考虑器兼容性,因为不同版本的C++标准实现的 STL都不一样,此时一般不作为可暴露参。
三、恶心的资源回收问题
多个dll之间的资源维护, dll-A 创建资源 供 dll-B 使用并持有该资源,在 dll-B 里直接对该资源进行了回收,这是不正确的,因为不同的 dll/exe 分属不同的模块,其内部的数据、堆栈也是相互独立,资源的创建与释放必须在同一个 dll/exe 模块内,否则会出现 【地址访问冲突】Access Violation at Address。
C语言的做法是 dll-A 通过malloc 创建对象,供dll-B 使用并持有该资源,进行回收时,dll-B 将该资源交回给dll-A 进行正确的资源回收。
C++ 语言的做法是 dll-A 通过new 创建对象,并通过引用计数(智能指针)对该对象进行包装、绑定资源回收函数,dll-B 使用并持有该资源,因为使用了引用计数,在dll-B 卸载时无需显示调用资源回收相关的函数,完完全全有引用计数自动处理。
四、在开发期间,适当提高编译警告,尽早规避问题
1、解决方案的CMakeLists.txt 只在Unix 环境下开启了 全级别的警告级别 -Wall, Windows的vs环境则默认为 /W1(建议调整为不比 Unix的警告级别, 因为我们都在windows下进行开发,应该尽早在开发期间发现问题,尽量避免出现在不同环境下编译结果不一致的情况);
2、将编译警告C4715(warning C4715:not all control paths return a value,不是所有的控件路径都返回值)强制改为 Error错误级别; 因为如果一个路径没有直接指明返回值的话, 编译器会根据返回值类数据类型的默认值,但是不同编译器对默认值的生成不一样,一些是0xcdcdcdcd, 一些是0,即使是同一编译器的不同版本的实现也会不一致;会出现一种潜在性的问题, 在windows下编译运行正常, 但在其他编译器编译运行后,却出现了异常!例如:
3、NFCMysqlDriverManager::AddMysqlServer() 内部出现了资源泄漏: 没有对new NFCMysqlDriver对象进行回收!没有正确使用多态(基于继承的运行时多态),PT项目的编程模式是【面向接口编程】,如果 NFIMysqlDriver/NFINet 基类没有提供virtual 析构函数,编译器会自动构造【默认非virtual析构函数】,在进行delete操作时,就会只调用 NFIMysqlDriver 的【默认非virtual析构函数】,子类(具体实现类)的析构函数不会被调用/部分成员函数没有释放,进而造成资源泄漏。在vc++下有 /Wall: C4265 编译警告 class has virtual functions, but destructor is not virtual instances of this class may not be destructed correctly,gcc 下/Wall 是 deleting object of abstract class type ‘*****’ which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor], 也建议将此警告强制为 错误error。
网友评论