从其它平台迁移而来
事件
计划做一个插件式的桌面应用框架,一方面练练手,另一方面算是自身的技术积累吧。
在练手过程中,发现一个巨难受的问题,dll
卸载不掉,程序直接假死!
虽然可以不直接调用卸载,依赖主程序退出时卸载的特性,但做为插件式应用,必须能在运行中加载/卸载才算完整。即便不是插件式应用,dll
的正常卸载也应该是很常用的功能,现在不正常,那么一定是代码写得有问题。
写了测试Demo,一行一行加代码,结果都能正常卸载,这就杯具了……测试了无数次,直到想把每一步都输出到日志时,dll
无法卸载了。一点点分析源码后,发现很可能是日志中为了方便使用,加的initialization
节和finalization
节导致的,注释掉之后就真的正常了。
分析
initialization
节应该是在Application.Initialize;
时执行的,finalization
节应该是在Application.Terminate;
之后的某个时间点执行的(具体执行时机没深入研究过)。而我的dll
是要做成插件的,不可避免会有可视化窗体,所以Application.Initialize;
不可避免(Lazarus
是这样,Delphi
不是),而在initialization
节中创建了日志记录器实例,在finalization
节中进行释放,这样,在卸载dll
时就出现了锁死的情况:卸载时有内存(实例)未释放,需要等内存释放了才能完全卸载,而未卸载又导致执行不到finalization
节,就不能释放实例……于是,dll
无法卸载,程序就进入假死状态。
以上只是初步分析,鉴于对底层机制了解不深,可能分析不完全正确,甚至是错误的。
结论
- 在编写的
dll
中不要在initialization
节和finalization
节中进行内存管理的工作。
对于无对象、纯函数式的dll
,initialization
节和finalization
节会不会产生影响尚未测试,目前也暂无这方面需求,待以后遇到了再详细测试吧。