首页 / 交易学院 / 小布知识库 / MQL5 对象生命周期:创建与析构顺序
MQL5 对象生命周期:创建与析构顺序
🔁

MQL5 对象生命周期:创建与析构顺序

全局/局部/动态三类对象的创建与析构规则与避坑

MQL5 编程 难度 · 进阶 2026-07-15 10 分钟阅读
#MQL5#OOP#对象#析构#内存

MQL5 基于面向对象编程,对象分全局、局部、动态三类,析构都按“与构造相反”的顺序。理解这套规则,是写出不漏内存、不崩盘的 EA 的基础。

一、三类对象的创建与析构

二、全局与局部的统一规则

无论全局还是局部,析构都按与构造相反的顺序进行;若某程序块没执行(如 input 开关为 false),里面的局部对象根本不会被创建。

✦ 查错口诀
记住“构造顺序=声明顺序,析构顺序=反着来”,遇到 undeleted objects 或 invalid pointer 日志时,先对照这个规则查。

三、动态对象的责任在你

四、指针数组的坑

多个指针数组指向同一 new 对象时,只能删一次,第二次删报无效指针;漏删则日志报 N undeleted objects left。

⚠ 声明顺序影响安全
若含指针数组的类对象先于原数组对象声明,它析构时原数组已没,指针失效。调换声明顺序即可避免。

五、组合类的正确姿势

六、生命周期与资源释放

指标句柄、文件句柄都要成对释放:OnInit/OnStart 里创建,OnDeinit 里 IndicatorRelease / FileClose,否则反复加载会泄漏。图表对象(OBJ_*)在图表关闭时由终端自动删除,但切换品种或周期会重建,别在对象里缓存跨周期状态。

✦ 调试技巧
在 OnDeinit 打印已释放的句柄数,若每次重载都在涨,就说明确实漏了 Release——这是对象生命周期类最常见的隐性 bug。

七、OnInitialize 与 OnDeinitialize 的时机

MQL5 程序的生命周期由终端管理:加载时调 OnInit(指标)或 OnInitialize(EA/脚本),卸载或重编译时调 OnDeinit / OnDeinitialize。资源的申请放前者、释放放后者,成对出现才不会泄漏。

实务中常见错误:在 OnInit 里打开了文件或指标句柄,却忘了在 OnDeinit 里 FileClose / IndicatorRelease,下一次加载就句柄堆积、文件被占用。把「每次初始化申请了什么」列个清单,对应写在反初始化里释放,是最稳的纪律。

八、标准库对象的构造与析构实践

CTrade、CChart、CArray 这类标准库对象,通常作为 EA 的全局成员,在 OnInit 构造一次、全程复用,不要在 OnTick 里反复 new。析构由终端在卸载时自动调用,你只需保证它们引用的底层句柄已被正确释放。

✦ 全局单例
跨事件共享的状态(持仓标记、句柄、计数器)统一收进全局对象,构造一次、复用全程,避免每 tick 重建带来的状态丢失与性能浪费。

九、资源泄漏的常见来源与排查

三类最易漏:一是文件句柄(FileOpen 后没 Close,多次加载后写不进);二是指标句柄(iCustom 反复调用不释放,句柄号耗尽);三是动态数组越界导致程序异常退出,析构来不及跑。

排查方法:在 OnDeinit 里打印当前还持有几个文件/句柄,或在任务管理器看终端句柄数是否随 reload 单调上涨。定位到具体资源后,补上对称的释放代码即可。

十、小结

✦ 小结
对象生命周期的核心是「申请与释放成对」:初始化里开的文件、句柄、对象,反初始化里一一关掉。标准库对象全局构造一次复用,别在 OnTick 反复 new。守住这条,重载不再泄漏、程序不再莫名其妙卡死。

常见问题

这是 OOP 通用约定,保证依赖关系安全——后构造的可能依赖先构造的,所以先拆后者。
MQL5 退出时会回收,但日志会报警 undeleted objects left;长期运行的 EA 若反复 new 不删才会真泄漏。
区分 POINTER_DYNAMIC / POINTER_INVALID,删除前调用它判断,避免删到无效或已删指针导致崩溃。
只在一个地方负责 delete,另一个指针置空或标记不拥有,防止重复删除。
会。组合类里若持有指针成员的类先析构、而它指向的原对象已先被析构,就会访问失效指针;调顺序是最简单的修法。