我目前正在为Delphi服务器应用程序编写一个旧的代码库,其中我试图修复一个内存泄漏,该泄漏会导致服务器因内存不足而崩溃。分配的大小约为1MB,恰好每5秒发生一次。我在RAD Studio 10.2上工作,代码是用Delphi 10.2编写的。
我得到的唯一信息是,该应用程序最近从Oracle 11迁移到了Oracle 12,同时还对代码进行了一些更改。因为在我到达之前没有版本控制,所以我不能准确地指出导致泄漏的确切更改。
像Deleaker、FastMM或Memory Validator这样的工具都无法确定导致问题的确切分配。问题似乎出在与数据库通信的代码中,因为内存验证器报告oraciei12.dll
中的泄漏,但即使在修复了代码中的一些弃用警告后,它仍然没有得到修复。这些工具还受到某些DLL和已编译可执行文件的某些部分中调试符号不可用的限制。
我从以前的C/C++经验中熟悉Valgrind,但是由于使用Win32过程和调用VCL函数,代码不能在Linux上编译。
我还尝试了使用delphi-leakcheck
、SamplingProfiler
和gpprofile2017
,它们都由于不同的原因而失败(不支持多线程、无法捕获某些分配等)。
编辑:代码已经使用madExcept运行,并且设置了ReportMemoryLeaksOnShutdown
。然而,没有泄密的报道...也许那段记忆在某种程度上仍然是可及的?或者它是由不同的线程分配的,并且无法被MadExcept检测到?此外,FastMMUsageTracker由于多线程而失败,并且VMMap不会显示内存分配位置的确切细节。
代码通过预处理器指令引用CodeSite,但与RAD Studio捆绑在一起的CodeSite版本不跟踪内存使用情况。
有没有其他方法来确定这次泄漏的根本原因?
1条答案
按热度按时间332nm8kg1#
您可以尝试从您正在使用的OCI客户端切换到另一个客户端,以查看泄漏来自Delphi OCI客户端库,该库可能不会释放资源。
我的建议是,尝试通过创建一个重现问题的最小项目来缩小问题的范围。例如,访问数据库并运行触发泄漏的语句。然后通过注解一些函数调用来缩小范围,进入嵌套调用,直到找到罪魁祸首。
如果它来自后台线程(每5秒运行一次?),那么您可以检查该线程的
Execute
方法,以及它如何初始化OCI层。也许Oracle客户端库需要一些特定的线程初始化或结束(例如,语句缓存),而这在生命周期较短的子线程中没有正确完成。