我有一个函数,它将另一个函数作为参数。像这样:
public function onHits(target : Shape, callback : Function) : void
我通过传递一个成员函数作为参数来使用它,只要传递的目标命中某个东西就应该调用它。该函数被一次调用多次。所以它通过以下方式使用:
//code...
CollisionManager.onHits(myShape, onHitCB);
//code...
点击功能:
public function onHitCB(hitObject : *) : void
{
//removed all code to test this problem
}
当我这样做时,我有内存泄漏。我已经将问题与onHits方法隔离开来,并已注释掉其他所有内容。 onHits是一个空方法,里面没有代码,onHitCB也是空的。如果我注释掉对onHits的调用,则没有内存泄漏,如果我传递null而不是onHitCB,则没有内存泄漏。
所以当我将onHitCB作为参数传递给问题时,显然是这样。所以我认为这可能是因为Flash分配了一些内存来创建Function指针并且不释放它但是我在调试模式中每一帧调用System.gc()并且泄漏仍然存在。这意味着这可能是SDK中的错误,或者我没有做正确的事情。
通过保留一个指向我在对象的构造函数中指定的函数的变量,我找到了一个奇怪的解决方法:
private var func : Function;
public function MyObject()
{
func = onHitCB;
}
这将清除内存泄漏,即使我仍将onHitCB作为参数传递。那么这意味着获取onHitCB不是“getter”函数,而是导致内存泄漏的其他东西?
我很困惑。这怎么会导致内存泄漏:
public function MyObject()
{
}
public function update() : void
{
CollisionManager.onHits(myShape, onHitCB);//empty function
}
public function onHitCB(hitObject : *) : void
{
//removed all code to test this problem
}
但不是吗? :
private var func : Function;
public function MyObject()
{
func = onHitCB;
}
public function update() : void
{
CollisionManager.onHits(myShape, onHitCB);//empty function
}
public function onHitCB(hitObject : *) : void
{
//removed all code to test this problem
}
并且有没有办法不必执行此解决方法?
答案 0 :(得分:5)
将方法作为参数传递时,会自动创建[...]绑定方法。绑定方法确保this关键字始终引用定义方法的对象或类。 Source
这听起来像创建对方法的引用并不是使用简单的getter。 生成的新方法闭包对象。所以你的假设是正确的。
我想知道为什么没有为每个实例缓存引用以及为什么它们不是垃圾收集的。最好避免创建多个引用。仅仅引用一次方法就像我在多个地方使用该方法时所做的那样,所以大多数时候我不会称之为解决方法,而是一种良好的干练习。在你的例子中,它是有道理的,假设一个方法引用将使用一个简单的getter。
答案 1 :(得分:1)
有关使用功能技术时确实会导致内存泄漏的详细信息,请查看http://www.developria.com/2010/12/functional-actionscript-part-1.html。此外,请注意使用这样的静态方法实际上是不好的做法(http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/),而你刚刚开始遇到使用这种技术引起的许多问题。听起来你在项目中已经足够早,你还没有完全致力于这条道路,所以你可能想看看其他方法来编程。
答案 2 :(得分:0)
我不确定你的代码是关于onHits函数的,但是如果它不需要额外的时间来完成另一个循环。然后我建议你这样做:
static public function onHits(target : Shape) : *
{
// do what you need
// return the hitObject;
return hitObject;
}
和
public function update() : void
{
// parse the object direc to to the function.
onHitCB ( CollisionManager.onHits(myShape) );
}
public function onHitCB(hitObject : *) : void
{
if ( hitObject == null )
return;
// if it not null then do all your calculations.
//removed all code to test this problem
}
答案 3 :(得分:-1)
这就是我们在OOP风格编程中不做这种事情的原因
最好的办法是正确地完成它并将回调添加到CollisionManager类。
当你保留本地引用时它可以被GCed的原因是因为函数永远不会丢失范围,因为var存在引用。<登记/>
一旦某些东西失去范围,GC就几乎不可能了
试试这个,看看你如何失去范围。
private var somevar:String = 'somevar with a string';
public function MyObject()
{
}
public function update() : void
{
CollisionManager.onHits(myShape, onHitCB);//empty function
}
public function onHitCB(hitObject : *) : void
{
trace(this.somevar) // scope should be lost at this point and somevar should be null or toss an error.
}