Delphi中在事件处理器内释放Sender(TCatcherServer实例)是否合规?
Delphi中TCatcherServer实例释放问题解答
这种做法不正确。
原因很直接:当OnFieldsReady事件在TCatcherServer的Callback方法里触发时,TCatcherServer的内部代码大概率还没执行完(比如Callback方法的后续逻辑仍在运行)。这时候直接在事件处理函数里调用Sender.Free释放实例,会导致后续TCatcherServer的代码尝试访问已被释放的内存,轻则触发内存访问错误,重则直接导致程序崩溃。
正确的实现方式主要有以下几种:
延迟释放,避开当前执行流程
不要在事件处理函数里直接Free,而是把释放操作放到当前调用栈之外执行。比如用TThread.Queue把释放任务放到主线程的消息队列里,等TCatcherServer的Callback方法完全执行完后,再执行释放:procedure TMainForm.FieldsReadyHandler(Sender: TObject); begin // 先获取所需数据 // ... // 延迟释放实例 TThread.Queue(nil, procedure begin Sender.Free; end); end;也可以给窗体发送自定义消息,在窗体的消息处理函数里再执行
Sender.Free,效果一致。让TCatcherServer自行管理销毁
修改TCatcherServer类的逻辑,在Callback方法触发OnFieldsReady事件之后,确认事件处理完成,再由类内部调用Free。不过这种方式要注意,如果事件处理是异步执行的,得确保实例不会在事件处理完成前被提前销毁。用引用计数自动管理生命周期
如果TCatcherServer可以改成继承自TInterfacedObject,那么用接口来持有这个实例,就不用手动调用Free了——当最后一个接口引用被释放时,实例会自动销毁,从根源上避免手动释放的风险。
内容的提问来源于stack exchange,提问作者Arthur Araujo
相关产品推荐
相关产品推荐

