2010-08-30 27 views
6

disculpas si esto es un engaño; no pude encontrarloAS3 - ¿Cuándo se ejecuta el recolector de basura?

que he leído y entendido el blog concesión de Skinner en el colector de basura AS3 - http://www.adobe.ca/devnet/flashplayer/articles/garbage_collection.html, pero mi pregunta no está cubierto allí.

aquí está mi pregunta.

Supongamos que yo he escrito algo de código AS3 como:

statementOne; 
statementTwo; 

¿hay alguna posibilidad de que el recolector de basura se ejecutará durante o entre mis dos declaraciones, o sólo correr detrás de mi código "usuario" tiene terminado y devuelto el control hasta el flash?

tenemos un bloque de código A-Star que a veces es lento, y me gustaría eliminar el GC como posible culpable. el bloque de código es, obviamente, más complejo que mi ejemplo anterior, , pero no implica ningún evento u otra cosa asincrónica.

tia, Orion

+0

querida Orion, GC no lo salvará de pérdidas de memoria, por lo que preferiría consejos para utilizar un generador de perfiles, p. Flash Builder Profiler para reescribir su bloque de código lento para codeblock más rápido, porque tendrá diferentes usuarios de su aplicación, y se deben notar como mínimo para el uso de memoria dura de su aplicación en su lugar. – Eugene

+0

gracias por el comentario, Eugene. mi pregunta no se trata de pérdidas de memoria, se trata de tratar de eliminar el GC como una posible causa de un problema particular de rendimiento que estoy teniendo. –

Respuesta

5

Aquí hay muchas buenas respuestas, pero creo que algunas sutilezas no se han abordado.

  1. El reproductor de Flash implementa dos tipos de recolección de basura. Uno es el conteo de referencias, donde Flash registra las referencias entrantes de cada objeto y sabe que cuando el conteo llega a cero, el objeto puede liberarse. El segundo método es el barrido de marcas, donde Flash ocasionalmente busca y elimina grupos de objetos aislados (donde los objetos se refieren el uno al otro, pero el grupo como un todo no tiene referencias entrantes).
  2. Como una cuestión de especificación cualquier tipo de recolección de basura puede ocurrir en cualquier momento. El jugador no garantiza cuándo se liberarán objetos, y los barridos de marcas pueden distribuirse en varios cuadros. Además, no hay garantía de que el tiempo de los GC permanezca igual entre las versiones de Flash Player, o las plataformas, o incluso los navegadores. Entonces, de alguna manera, no es muy útil saber nada sobre cómo se activan los GC, ya que no hay forma de saber qué tan ampliamente aplicable es su conocimiento.
  3. Dejando a un lado el punto anterior, en general, los barridos de marcas son poco frecuentes y solo se desencadenan en determinadas circunstancias. Conozco ciertas configuraciones de reproductor/sistema operativo donde una marca/barrido podría activarse cada N segundos, o siempre que el jugador excediera el P% de la memoria total disponible, pero esto fue hace mucho tiempo y los detalles habrán cambiado. Los GC de recuento de referencias, en contraste, pueden ocurrir frecuentemente, entre cuadros, al menos. No creo que los haya visto demostrar que ocurren con más frecuencia, pero eso no significa que no pueda ocurrir (al menos en ciertas situaciones).

Finalmente, una palabra sobre su problema específico: en mi experiencia es muy poco probable que el GC tenga algo que ver con su problema de rendimiento. El procesamiento de GC con recuento de referencias bien puede ocurrir durante sus bucles, pero generalmente esto es algo bueno: este tipo de recopilación es extremadamente rápida y mantiene el uso de la memoria manejable. El objetivo de administrar sus referencias cuidadosamente es garantizar que este tipo de GC ocurra de manera oportuna.

Por otro lado, si ocurre una marca/barrido durante sus bucles, eso ciertamente afectaría su rendimiento. Pero esto es relativamente difícil de confundir y fácil de probar. Si está probando en una PC y su aplicación no sube regularmente a los cientos de MB de uso de memoria (prueba con System.totalMemory), es probable que no obtenga ninguna marca/barrido en absoluto. Si los tiene, debería ser fácil verificar que las pausas asociadas son grandes, poco frecuentes y siempre van acompañadas de una gran reducción en el uso de la memoria. Si esas cosas no son ciertas, puede ignorar la idea de que GC es parte de sus problemas.

+0

Hehe, si hubiera hecho clic en el enlace del autor de la pregunta antes de responder, habría visto que gran parte de esto estaba cubierto. Bueno, espero que los dos últimos párrafos aún sean útiles. – fenomas

+0

excelente, gracias por la respuesta reflexiva. en general, parece que es muy poco probable que el GC sea parte del problema de rendimiento esporádico que estoy viendo, ¡que es algo muy bueno! Puedo arreglar mi código, pero no puedo arreglar el GC. Muchas gracias por las respuestas. –

0

No se puede determinar cuándo se ejecutará GC. Si intenta evitar que algo sea GC, mantenga una referencia en algún lugar.

+0

hola, gracias por la respuesta. Sé que no puedo determinar en el gran esquema de cosas cuando se ejecuta el GC, pero mi pregunta es si puedo saber que no se ejecutará en el medio de ejecutar decir "x + = 1". –

+1

¿Tiene Flex Builder? Tiene un perfilador de memoria que puede responder algunas de sus preguntas. – ThatSteveGuy

1

Que yo sepa, esto no está documentado. Tengo la sensación de que el GC no se ejecutará mientras se está ejecutando el código (es decir, mientras el código está en la pila de ejecución, cada fotograma, el jugador crea una nueva pila para el código de uso). Obviamente, esto proviene de la observación y mi propia experiencia con Flash, así que no diría que esto es 100% exacto. Con suerte, es una suposición educada.

Aquí está una prueba simple que parece demostrar que lo anterior es cierto:

package { 
    import flash.display.Sprite; 
    import flash.net.FileReference; 
    import flash.system.System; 
    import flash.utils.Dictionary; 
    import flash.utils.setTimeout; 

    public class test extends Sprite 
    { 

     private var _dict:Dictionary = new Dictionary(true); 

     public function test() 
     { 
      testGC(); 
      setTimeout(function():void { 
       traceCount(); 
      },2000);    
     } 

     private function testGC():void { 
      var fileRef:FileReference; 
      for(var i:int = 0; i < 100; i++) { 
       fileRef = new FileReference(); 
       _dict[fileRef] = true; 
       traceCount(); 
       System.gc(); 
      } 
     } 

     private function traceCount():void { 
      var count:int = 0; 
      for(var i:* in _dict) { 
       count++; 
      } 
      trace(count); 
     } 

    } 
} 

La GC parece ser particularmente codicioso cuando hay FileReference objetos involucrados (de nuevo, esto es desde mi experiencia, esto no es' t documentado por lo que yo sé).

Ahora, si ejecuta el código anterior, incluso si llama explícitamente System.gc(), los objetos no se recopilan mientras su función está en la pila: puede ver que todavía están vivos mirando el recuento del diccionario (que se establece usar referencias débiles por razones obvias).

Cuando se vuelve a rastrear este recuento, en una pila de ejecución diferente (causada por la llamada asincrónica a setTimeout), todos los objetos se han liberado.

Por lo tanto, diría que parece que el GC no es el culpable del bajo rendimiento en su caso. De nuevo, esto es una mera observación y el hecho de que el GC no se ejecutó mientras se ejecutaba el código de usuario en esta prueba no significa que nunca lo hará. Probablemente, no lo hará, pero dado que esto no está documentado, no hay forma de saberlo con certeza, me temo. Espero que esto ayude.

+0

impresionante, gracias por la investigación. Creo que tienes razón. –

+0

también, he escuchado y verificado experimentalmente que System.gc() simplemente solicita al sistema que haga un barrido, y en mis pruebas, por lo general, se ignoró. –

+0

@orion elenzil. En mi experiencia, el gc casi siempre se ejecuta (ya sea que lo llame desde el código o desde el generador de perfiles de FlexBuilder). Sin embargo, hay algunas advertencias. Debes jugar el swf con la versión de depuración del reproductor y, a veces, parece que necesitas llamarlo dos veces para que se ejecute (¡imagínate!). Además, lo más probable es que se ejecute con un retraso de todos modos (probablemente después de que se haya ejecutado el código de usuario). –

1

GC no se ejecutará entre dos sentencias que están en la misma pila/el mismo marco que tiene en su ejemplo. La memoria se liberará antes de la ejecución del siguiente fotograma. Así es como funcionan la mayoría de los entornos de VM modernos.

+0

No. En realidad, estoy diciendo que un gc en una versión moderna no va a gastar procesamiento para ejecutar la liberación innecesaria entre las declaraciones. Flash, iPhone, Java y .net son modernos en mi opinión modernos. Esperan hasta que duerme el hilo, las pilas se completan o termina Runloops. – tidwall

+0

¡El iPhone no tiene un GC! –

+0

@TandemAdam Por supuesto. Me refiero al grupo de memoria, no a GC. – tidwall

6

El recolector de basura no está enhebrado, por lo que, en términos generales, no se ejecutará mientras se ejecuta el código. Sin embargo, hay un caso excepcional en el que esto no es cierto.

La palabra clave new invocará al recolector de elementos no utilizados si se queda sin memoria.

Puede ejecutar este código para observar este comportamiento:

var vec:Vector.<*> = new Vector.<*>(9001); 
for (;;) { 
    vec[0] = new Vector.<*>(9001); 
    vec = vec[0]; 
} 

Uso de memoria saltará rápidamente hasta el máximo (1 GB para mí) a continuación, mantenga hasta que el corte de tiempo.

+0

dulce, gracias. –

+0

+1. Esa es una prueba mejor que la que se me ocurrió. ¡No había pensado en la fuerza bruta 'nueva'! –

0

De acuerdo con este Tom from Gabob, las jerarquías huérfanas lo suficientemente grandes no reciben basura recolectada.

Cuestiones relacionadas