lua C++循环引用导致的内存泄露及解决方案

本文通过一个最常见的,lua和C#/C++循环引用导致的内存泄露案例来分析原因和解决方案。

循环引用案例

按钮绑定匿名函数(闭包)导致的循环引用:

self.Button.OnClicked:Add(function()
    self:doSomething(true)
end)

原因

循环引用链:

UIBP(self)------->Button------>luaFunction------>UIBP(self)

lua引用到C++对象Button,Button又引用到了lua的闭包,闭包内使用了一个upvalue——self,而这个self指的是一个UIBP,UIBP又引用到了Button

简单来说就是lua函数引用到了C++对象,这个C++对象又引用回了同一个lua函数。导致GC检测引用的时候,这个UI始终无法被回收

解决方案

解除循环引用链中的某一个引用即可

解绑

self.Button.OnClicked:RemoveAll()

解除委托的绑定以后,就不存在Button对luaFunction的引用了,也就打破了循环引用链:

UIBP(self)------->Button—×—>luaFunction------>UIBP(self)

保证绑定的luaFunction中没有强引用到自身

使用弱引用传递self

function UIBPName:f1()
	self:doSomething(true)
end

self.Button.OnClicked:Add(self.f1, self)

Add方法对第一个参数是强引用,第二个参数则是弱引用。相当于打破了循环引用链:

UIBP(self)------->Button------>luaFunction—×—>UIBP(self)

对第一个参数强引用的原因是,保证匿名函数可以作为第一个参数传入。

方法中不使用强引用self

local f1 = func()
	UIBP:doSomething(true)
end

self.Button.OnClicked:Add(f1)

这种方式可以保证即便忘记解绑,也不会出现内存泄露

Tips
这种 local f1 最好不要写在函数里面,防止上值存储

猜你喜欢

转载自blog.csdn.net/weixin_44559752/article/details/125448294
今日推荐