Flex/AS3 – Truques e Dicas #9 – Weak Reference / GC

Flex/AS3 – Truques e Dicas #9 – Weak Reference / GC

Um dos aspectos que mais incomodam no flash, principalmente em aplicações que são usadas ao longo de bastante tempo, e que usam muitas funções dinamicas, é o facto de a memória utilizada pelo projecto ser consideravel, e se não tomamos cuidado, facilmente ela aumenta e pode até mesmo impedir que o projecto se execute normalmente e em alguns casos que o flash simplesmente faça com que o browser deixe de funcionar.

Existem muitos pontos onde podemos poupar o motor do flash, e não vou falar de todos mas apenas de 2, o weak reference em eventos e a atribuição de null.

Estes pontos trabalham directamente com o “core” do flash e podem poupar muitas dores de cabeça, embora eu não os use sempre, é importante que os conheçam no caso da sua aplicação ser comercial visto que pode poupar algumas dores de cebeça.
O flash possui um sistema de recolha de lixo, chamado de garbage collector ou apenas GC, ou seja, dentro da maquina virtual, periodicamente é vasculhado todo o código da aplicação à procura de elementos que já não sejam usados e no caso de encontrar algum o eliminar da memória, fazendo com que não seja ocupada memória desnecessária. Embora este sistema seja de extrema importancia ele contém algumas falhas e não faz o seu trabalho como deve ser… (não vou falar porque visto que é uma assunto muito debatido). Para evitar-mos uso da memória sem necessidade existem alguns truques, como o re-uso do código, arquitecturas de código bem feitas e exclusão de código desnecessário.

O weak reference, é uma “marca” que se pode atribuir a um evento, que faz com que o GC esteja atento a ele, e se este não for necessário o GC elimina-o… isto é muito util, visto que um eventListener é algo que usa memória, e por sinal, alguma memória… Por defeito o GC não elimina Listeners da memória, teriamos que o fazer manualmente usando o removeEventListener, não é que já não precisemos do removeEventListener, mas no caso de nos esquecer-mos de o escrever, o weakreference é uma óptima alternativa porque vai remover o listener automaticamente se este não for mais usado. Basta criarem os vossos eventos assim:

[coolcode] meuObjecto.addEventListener(MouseEvent.CLICK, minhaFuncaoEscuta, false, 0, true);
[/coolcode] onde o true indica que o evento deve ser marcado como weak reference, fazendo com que possa ser removido pelo GC. Todos os eventos podem ser considerados como weak references.

O weak reference, infelizmente apenas está disponivel nos eventos e em mais uma class, dictionary, mas que pouca gente usa. Embora tenha encontrado um hack que torna todos os objectos passiveis de serem marcados como wek Reference, este não me convenceu da sua real utilidade. Para quem estiver interessado em testar, veja o post aqui.

Outra dica é não deixar elementos soltos, ou seja, se uma variavel ou objecto não são mais necessários, elimine-os marcando-os como null.

Por exemplo:
[coolcode] private var minhaVar1:Boolean;

minhaVar1=true;
[/coolcode]

Imaginem que apenas precisamos desta variavel uma unica vez, a maior parte das vezes deixa-mo-la assim, usamos e esquecemos a mesma, mas este pensamento está errado, porque apesar de não a usarmos mais, esta vai ficar sempre na memória, e não vai ser eliminada pelo garbage collector porque ela possui um valor… Mas podemos mudar este habito, e melhorar o desempenho da nossa aplicação, colocando:
[coolcode] minhaVar1=null;
[/coolcode] Desta forma a variavel será eliminada da memória pelo GC porque esta não possui nenhum valor.

A principal coisa a ter em mente é nunca esquecer de eliminar código que não seja necessário, eventos ou propriedades… depende de cada programador faze-lo, considerando sempre essa possibilidade principalmente quando a aplicação têm objectivos comerciais.

Embora existam alguns truques e inclusive um comando para executar o GC, este não aparenta melhorar o desempenho se não tomar-mos algumas das precauções em cima, mas para quem quiser testar a sua utilidade, por exemplo a seguir a alguns addChilds/removeCHild’s, basta escrever o código seguinte (apenas funciona nas versões debugger do flash e no AIR, nunca entendi porque não funcionam no flash player normal.):
[coolcode] flash.system.System.gc();
[/coolcode] ou usar um hack que já o vi funcionar, mas não parece ser muito lógico de usar em aplicações finais:
[coolcode] private function gcHack():void
{
try
{
var lc1:LocalConnection = new LocalConnection();
var lc2:LocalConnection = new LocalConnection();
lc1.connect(‘name’);
lc2.connect(‘name’);
}
catch (e:Error) {
}
}
[/coolcode] Este código, repetindo o localConnection parece disparar o GC, mas bom…visto que nao se pode garantir quaisquer vantagens em usa-lo, terá que decidir de o usar ou não.

Bom, espero que seja util.

Cumprimentos.


3 comments

add yours
  • Brian April 15, 2009

    Boas, Mário, uma dúvida:
    E quando esses eventos são declarados no MXML ? Não há maneira de usar weak reference ?

  • Robson April 24, 2009

    Post muito interessante Mário.
    Utilizo Flex na empresa em que trabalho, e foi comentando em usar Gc, porém não sabia que a Plataforma Flash possuia esse recurdo de forma manual, achava a plataforma efetuava esse trabalho de forma automatizada sem a liberação de métodos especificos para o desenvolvedor implementar.

    Abraços.

  • Mário Santos April 24, 2009

    Brian, usar no MXML como?

    Robson, o flash têm um garbage collector, e este funciona de forma automatica (sempre que o uso da memória dispara em alguns mb, ou periodicamente, acho…. ) mas deixa muito “lixo” devido à sua “fraca” forma de identificar o que deve remover, e por isso podemos dar uma ajuda identificando o que possamos para ser eleminado…

Leave a Comment

Post