Archive Page 2
Muita gente já ouviu afirmações do tipo “Flash é pesado!”, sem saber exatamente o porquê. Na maioria das vezes, a culpa é do desenvolvedor que, por não saber como o player funciona e não se preocupar em manter boas práticas de programação, acaba sobrecarregando a RAM e CPU. Tentarei explicar como podemos otimizar nossas aplicações, mas antes, vamos entender o que acontece por trás.
Antigamente, o player não tinha o costume de consumir muita RAM, o problema recaía no uso pesado do processador (que melhorou com o Player 10, que começa a usar recursos da placa de vídeo) mas temos uma série de novos recursos (ByteArray, BitmapData…) que podem consumir muitos megas da memória. Além disso, desde o ActionScript 2 o Garbage Collector (GC) do flash tem dificuldades em manter a RAM limpa, pelo próprio modo como as referências internas são feitas, como explicado pelo Jim Corbett neste vídeo em (25:30):
Mas afinal, o que é o Garbage Collector e como ele funciona?
O GC é o processo que limpa a sujeira que você deixou pra trás: ele retira da memória objetos que não serão mais usados pela aplicação. E como ele fica sabendo disso? Bem, atualmente isso é feito no flash de duas maneiras distintas: Reference Counting e Mark Sweep.
O mais simples dos métodos, o Reference Counting era usado desde o Actionscript 1.0, e a idéia é bem prática: toda vez que alguém faz referência a um objeto (ou seja, provavelmente será usado), um contador de uso do objeto é acrescido de 1. Toda vez que uma referência é retirada, esse contador é decrescido de 1. Desse modo, quando não há nada fazendo referência ao objeto (o contador voltou a 0), ele é marcado para ser retirado da memória. Exemplo:
var obj1:Object = {var1:"oi"}; // contador em 1, o objeto está sendo referenciado por obj1
var obj2:Object = obj1; // contador em 2
delete obj1; // contador em 1, não está mais sendo referenciado por obj1
trace( obj2.var1 ); // retorna "oi". Como pode ver, o objeto e referências a ele são coisas distintas
delete obj2; // contador em 0. aqui o objeto é alvo do GC para remoção
Algumas observações:
- Como podem ver, o objeto e a variável que guarda o objeto são coisas distintas. Mesmo se não houver nada fazendo referência a { var1:”oi” }, ele não deixa de existir. Por isso a importância do Garbage Collector.
- Quando ninguém mais “fala sobre” o objeto (referência a variáveis, escutas de evento, enterFrames…), é uma justificativa para ele ser jogado fora. Mas podem haver casos onde o objeto é referenciado, mas não é mais usado.
Pense no seguinte cenário: A guarda B, B guarda C e C guarda A. No final das contas, pode ocorrer o caso de nenhum deles ser mais utilizado, mas todos estão sendo referenciados no código, logo não serão retirados da memória. Para corrigir esse problema, outra técnica é utilizada: o Mark Sweep. Nesse método, o flash percorre a partir do root todos os objetos que consegue encontrar, recursivamente, e os marca. Se algum objeto não for marcado, significa que ele não está sendo utilizado. No caso que falei acima, se nem A nem B nem C tiverem uma ligação direta ou indireta com a raiz da aplicação, eles serão removidos da memória.
Note que limpar a memória é um processo lento, que percorre todos os objetos, logo não é acionado com tanta frequência: aproximadamente uma vez a cada 60 segundos ou quando a alocação de memória der um pulo maior que 20% o uso atual (dados não oficiais). De qualquer modo, não é previsível quando um objeto vai ou não ser removido da memória. Note que, enquanto o objeto existir, isso quer dizer que os loops, acessos a arquivos, sons, etc, continuação ser processados, então fica evidente a importância de se saber como manter a memória limpa.
Em meu próximo post tentarei explicar como podemos ajudar o GC do flash em seu trabalho.
referências:
http://blogs.eyepartner.com/adrian/flex/flex-tip-6-garbage-collection-in-flex/GC Flush em Flex
http://www.adobe.com/devnet/flashplayer/articles/garbage_collection.html gskinner falando sobre o GC
terrenos no flash - parte 3
Como eu falei, poucas mudanças fazem outra coisa totalmente diferente… diminuí o n do perlinNoise e deixei a cor da linha variar de acordo com o y:
stage.quality = "medium";
var noise:BitmapData = new BitmapData( 300, 1000 );
noise.perlinNoise( noise.width, noise.height, 2, Math.random() * 256, true, false, 7, true );
var container:Sprite = new Sprite();
container.x = 100;
container.y = 150;
addChild( container );
function createLine( bmd:BitmapData ):Sprite {
var line:Sprite = new Sprite();
line.graphics.beginFill( 0xFFFFFF, 1 );
line.graphics.lineStyle( 0, 0x000000, 0 );
line.graphics.lineTo( 0, -( bmd.getPixel( 0, 1 ) & 0xFF ) / 1.7 );
var ratio:Number;
for (var i:uint = 0; i < bmd.width; i +=2) {
ratio = ( bmd.getPixel( i, 1 ) & 0xFF );
line.graphics.lineStyle( 0, rgb2hex( 0, Math.min( ratio * 3 + 102, 255 ), Math.min( ratio * 3 + 102, 255 ) ), 1 );
line.graphics.lineTo( i, -ratio / 2.2 );
}
line.graphics.lineStyle( 0, 0x000000, 0 );
line.graphics.lineTo( i, 0 );
line.graphics.endFill();
return line;
}
var count:uint = 1;
function animate() {
var bmd:BitmapData = new BitmapData(noise.width, 2 );
bmd.copyPixels( noise, new Rectangle( 0, count, noise.width, 2 ), new Point() );
var elm:Sprite = new Sprite();
var line:Sprite = createLine( bmd );
line.x -= line.width / 2;
line.y -= line.height / 2;
elm.addChild( line );
elm.addEventListener( Event.ENTER_FRAME, onLineFrame );
container.addChild( elm );
container.scaleX = container.scaleY = 2;
container.x = 250;
container.y = 350;
count += 5;
if ( count >= noise.height - 1 ) {
count = 1;
}
}
function onLineFrame( e:Event ):void {
var elm:Sprite = e.target as Sprite;
var ratio:Number = elm.scaleY;
ratio -= 0.02;
elm.scaleX = ( ratio / 1.5 ) + 0.5;
elm.scaleY = ratio;
elm.y = -160 * ( 1 - ratio );
elm.alpha = ( ratio * 1.5 ) - 0.5;
if ( ratio <= 0.3 ) {
elm.parent.removeChild( elm );
elm.removeEventListener( Event.ENTER_FRAME, onLineFrame );
}
}
function rgb2hex( r:int, g:int, b:int ):Number
{
return ( r << 16 ) | ( g << 8 ) | b;
}
//animate();
setInterval( animate, 10 );
Terrenos no Flash - parte 2
Continuando a minha idéia, fiz o primeiro teste:
- Criei um PerlinNoise estreito e longo, com stitch = true pro final emendar no começo;
- Criei um método pra criar uma linha de acordo com um BitmapData de y = 1;
- Criei um método pra criar as linhas uma a uma a aprtir de “fatias” do PerlinNoise;
- Em cada linha, fiz um método pra montar o “3D”, diminuindo, movendo e aplicando alpha.
stage.quality = "medium";
var noise:BitmapData = new BitmapData( 300, 800 );
noise.perlinNoise( noise.width, noise.height, 7, Math.random() * 256, true, false, 7, true );
var container:Sprite = new Sprite();
container.x = 100;
container.y = 150;
addChild( container );
function createLine( bmd:BitmapData ):Sprite
{
var line:Sprite = new Sprite();
line.graphics.beginFill( 0xFFFFFF, 1 );
line.graphics.lineStyle( 0, 0x000000, 0 );
line.graphics.lineTo( 0, -( bmd.getPixel( 0, 1 ) & 0xFF ) / 1.7 );
line.graphics.lineStyle( 0, 0x000000, 0.2 );
for( var i:uint = 0; i < bmd.width; i +=5 )
{
line.graphics.lineTo( i, -( bmd.getPixel( i, 1 ) & 0xFF ) / 1.7 );
}
line.graphics.lineStyle( 0, 0x000000, 0 );
line.graphics.lineTo( i, 0 );
line.graphics.endFill();
return line;
}
var count:uint = 1;
function animate()
{
var bmd:BitmapData = new BitmapData(noise.width, 2 );
bmd.copyPixels( noise, new Rectangle( 0, count, noise.width, 2 ), new Point() );
var elm:Sprite = new Sprite();
var line:Sprite = createLine( bmd );
line.x -= line.width / 2;
line.y -= line.height / 2;
elm.addChild( line );
elm.addEventListener( Event.ENTER_FRAME, onLineFrame );
container.addChild( elm );
container.scaleX = container.scaleY = 2;
container.x = 250;
container.y = 350;
count += 5;
if( count >= noise.height - 1 ) count = 1;
}
function onLineFrame( e:Event ):void
{
var elm:Sprite = e.target as Sprite;
var ratio:Number = elm.scaleY;
ratio -= 0.01;
elm.scaleX = ( ratio / 1.5 ) + 0.5;
elm.scaleY = ratio;
elm.y = -160 * ( 1 - ratio );
elm.alpha = ( ratio * 1.5 ) - 0.5;
if( ratio <= 0.3 )
{
elm.parent.removeChild( elm );
elm.removeEventListener( Event.ENTER_FRAME, onLineFrame );
}
}
//animate();
setInterval( animate, 10 );
Search
You are currently browsing the Leandro Ferreira weblog archives.


