proyectos - para que sirve el programa flash
AS3 pasando una función como parámetro crea pérdidas de memoria (4)
Tengo una función que toma otra función como parámetro. Algo como esto :
public function onHits(target : Shape, callback : Function) : void
Lo uso al pasar una función miembro como un parámetro que se debe invocar cada vez que el objetivo pasado golpea algo. La función se llama muchas veces un marco. Entonces se usa haciendo:
//code...
CollisionManager.onHits(myShape, onHitCB);
//code...
La función de golpear:
public function onHitCB(hitObject : *) : void
{
//removed all code to test this problem
}
Cuando hago esto, tengo una pérdida de memoria. He aislado el problema con ese método onHits y he comentado todo lo demás. onHits es un método vacío sin código dentro, onHitCB también está vacío. Si desactivo la llamada a onHits, no hay pérdida de memoria y si paso null en lugar de en HitCB no hay pérdida de memoria.
Así que es claramente cuando paso en HitCB como un parámetro que es el problema. Así que pensé que podría ser porque Flash asigna un poco de memoria para crear el puntero a la función y no la libera, pero yo llamo System.gc () a cada cuadro en modo de depuración y la filtración aún está allí. Lo que significaría que esto es un error en el SDK o no estoy haciendo algo bien.
He encontrado una solución extraña al mantener una variable que apunta a la función que asigno en el constructor de mi objeto:
private var func : Function;
public function MyObject()
{
func = onHitCB;
}
y esto borrará la fuga de memoria incluso si aún pasoHitCB como parámetro . Entonces, ¿eso significaría que no es la función "getter" para obtener el onHitCB sino otra cosa que causa la pérdida de memoria?
Estoy muy confundido. ¿Cómo puede esto causar una pérdida de memoria?
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
}
pero no esto? :
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
}
y hay una manera de no tener que hacer esta solución?
[...] los métodos vinculados se crean automáticamente cuando pasa un método como parámetro. Los métodos enlazados garantizan que la palabra clave siempre haga referencia al objeto o clase en la que se define un método. Fuente
Eso suena como crear una referencia a un método que no utiliza un getter simple. Se genera un nuevo objeto de cierre de método. Entonces tu suposición es correcta.
Me pregunto por qué las referencias no se almacenan en caché para cada instancia y por qué no son basura. Mejor evitar crear múltiples referencias. Hacer referencia a un método solo una vez es exactamente lo que haría cuando tendría que usar ese método en varios lugares, por lo que la mayoría de las veces no lo llamaría una solución sino una buena práctica DRY. En su ejemplo, tiene sentido, por supuesto, suponiendo que una referencia de método usaría un getter simple.
No estoy seguro de cuál es tu código en la función onHits, pero si no requiere tiempo adicional para terminar en otro ciclo. entonces te recomiendo que hagas así:
static public function onHits(target : Shape) : *
{
// do what you need
// return the hitObject;
return hitObject;
}
y
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
}
Para obtener más información sobre qué hace y qué no causa pérdidas de memoria cuando utiliza técnicas funcionales, consulte http://www.developria.com/2010/12/functional-actionscript-part-1.html . Además, tenga en cuenta que el uso de métodos estáticos como este es realmente una mala práctica (http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/), y que recién está empezando a enfrentar los muchos problemas que se producen al usar esta técnica. Parece que ya has iniciado tu proyecto lo suficientemente temprano como para no estar completamente comprometido con este camino, por lo que es posible que desees buscar otras formas de programarlo.
Y es por eso que no hacemos este tipo de cosas en la programación de estilo OOP.
Su mejor opción es hacerlo correctamente y agregar la devolución de llamada a la clase CollisionManager.
La razón por la que se puede convertir en GC cuando se conserva una referencia local es porque la función nunca pierde el alcance porque esa var está allí con la referencia.
Una vez que algo pierde alcance, es casi imposible GC.
Prueba esto y mira cómo pierdes alcance.
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.
}