Autor Zpráva
RobertVarga
Profil *
Ahoj,
mam vetsi problem s memory leaky v jednoduchem js kodu, ktery v pravidelnych intervalech meni img.src u vybraneho obrazku.

Kod je jednoduchy a problem take - pri kazdem nacteni noveho obrazku dojde k memory leakum a proces iexplore si uzdibne dalsi a dalsi pamet.

Za nekolik minut neni problem se dostat az na 800MB.

IE8 (projevuje se vsak i ve FF, ovsem pomaleji), stranka je zde:

http://www.gamelot.cz/test.htm

Kod je zde:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
	<title>JS memory leak</title>
	<meta http-equiv="content-type" content="text/html; charset=windows-1250" />
	<meta http-equiv="Pragma" content="no-cache" />
	<meta http-equiv="expires" content="-1" />
	<meta http-equiv="Cache-Control" control="no-store">
</head>
<body>
	<img style="opacity:0.99;alpha(opacity=99);width:100%;height:100%;" src="sunset.jpg" alt="Zmen img" id="obrazek1" />

	<script language="Javascript" TYPE="text/javascript">

		tmrZmenObrazek = setInterval("zmenObrazek()",2000);

		function zmenObrazek(){
			funkce = function(){
				obr1 = document.getElementById("obrazek1");
				cas = new Date( )
				casAktualni = cas.getTime( );
				obr1.src = "sunset.jpg?rnd=" + casAktualni;
				obr1 = null;
				casAktualni = null;
				cas = null;
			}
			funkce();
			funkce=null;
		}
	</script>
</body>
</html>


Prohledal jsem internet, ale nic lepsiho jsem nevymyslel :-( Nevite nekdo, jak to udelat bez memory leaku?
RobertVarga
Profil *
Tak ranni zjisteni mne docela nastvalo :-(

"IE8 leaks memory when images resized" - http://www.vistaheads.com/forums/microsoft-public-internetexplorer-general/356292-ie8-leaks-memory-when-images-resized.html

Zkousel jsem to pres IE Tester a bohuzel problem se vyskytuje pouze v IE8 (Forefox OK, IE 5.5, 6, 7 OK).

Tak, a co ted? :-/
Chamurappi
Profil
Reaguji na RobertaVargu:
Zkus použít AlphaImageLoader.
RobertVarga
Profil *
V prvni rade moc diky za rychlou reakci.

Procetl jsem si nejake info o AlphaImageLoaderu a chtel bych je vedet, zdali je to cross-browser reseni - mas to vyskousene? Spokojenost.

Moc diky!
RobertVarga
Profil *
Tohle mi vubec nenacte obrazek, ackoli by to melo byt podle specifikace:

<div style="width:100%;height:100%;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='sunset.jpg', 'sizingMethod='scale');" id="obrazek1" />
RobertVarga
Profil *
Problem jsem vepsal na technet. http://social.technet.microsoft.com/Forums/en-US/ITCG/thread/2d1ccd07-3b7c-424e-98aa-52937d3bd930
Chamurappi
Profil
Reaguji na RobertaVargu:
chtel bych je vedet, zdali je to cross-browser reseni
Ne. AlphaImageLoader bys použil jen v osmičce. Nebo jen v Explorerech — funguje od verze 5.5.

mas to vyskousene?
Mám vyzkoušené, že AlphaImageLoader umí natahovat obrázky.

ackoli by to melo byt podle specifikace
Máš tam jeden apostrof navíc před „sizingMethod“. A také nemáš uzavřený <div> (ale to moc nevadí, zavře se sám s koncem dokumentu) — na to by tě upozornil validátor (ale bohužel ne ten na w3.org, ten si bude myslet, že používáš XHTML).
RobertVarga
Profil *
Jezis to jsem to pokonil (predelaval jsem img na div, omfg).

Kazdopadne diky za workaround, ja vsak verim, ze se problem vyresi na strane IE8.

Diky za pomoc a budiz s pozdravem,
hRobokop ;-)
Chamurappi
Profil
Reaguji na RobertaVargu:
ja vsak verim, ze se problem vyresi na strane IE8
Myslíš, že si vývojáři řeknou „hm, tak jo“ a s příštími aktualizacemi Exploreru dodají všem brouzdalům záplatu? Tomu bych moc nevěřil.

Kazdopadne diky za workaround
Takže to funguje?
_es
Profil
RobertVarga
Problém môže byť v riadku:
tmrZmenObrazek = setInterval("zmenObrazek()",2000);

Skús to zmeniť na:
tmrZmenObrazek = setInterval(zmenObrazek,2000);

Možno dochádza k vytváraniu stále nových objektov funkcií aj so všetkými ďalšími objektmi v nej a nie sú dosť efektívne "zahadzované". Možno však bude chyba niekde úplne inde, no toto ľahko vyskúšaš. Nastavovanie objektov na null je nadbytočné. Načo vytváraš funkciu funkce len na to, aby si ju zavolal?
_es
Profil
Vlastne sa to celé dá zjednodušiť na:
var obr1 = document.getElementById("obrazek1");
setInterval(function(){obr1.src = "sunset.jpg?rnd=" + (new Date).getTime();}, 2000);
RobertVarga
Profil *
chamurappi: Funguje, a neleakuje. Akorat specialnich casti scriptu volanych v zavislosti na pouzitem prohlizeci bych se chtel vyvarovat. Ale pokud to v MS nevyresi do Win7, tak to tak stejne dopadne :-) Moc diky za super pomoc!

_es: Ten muj script je vysledek vcerejsiho 4 hodinoveho badani. Protoze jde o ultimatni haluz, IE8-only bug, fakt jsem zkousel vse. :-( SetInterval vsak mam blbe, diky za tip.

Jeste jendou diky moc, pockam na MS, a zatim nejak zapracuju vase rady do "the B plan" ;-)
RobertVarga
Profil *
"Chamurappi: Myslíš, že si vývojáři řeknou „hm, tak jo“ a s příštími aktualizacemi Exploreru dodají všem brouzdalům záplatu? Tomu bych moc nevěřil."

Mne se uz jednou postestilo. S M$ TechNetem mam (mimo rychlost odezvy) skutecne supr zkusenosti.
_es
Profil
RobertVarga
Na začiatku píšeš, že sa to prejavuje miernejšie aj vo FF, takže môže ísť o nevhodný script. Pri vnorených funkciách môžu nastať rôzne komplikácie. Skús ten svoj celý script nahradiť tými dvomi riadkami, či sa to ešte bude prejavovať.
RobertVarga
Profil *
EDIT - IE8 mozna leakuje i s AlphaImageLoaderem.

Uprava kodu dle _es:

Je nastaveno width a height = IE8 memory leak:
http://www.gamelot.cz/test.htm

Neni nastaveno width a height = bez problemu:
http://www.gamelot.cz/testBez.htm

chamurappiho navrh AlphaImageLoader:

http://www.gamelot.cz/testAIL.htm

Bohuzel tady v praci mi pres IETestera AlphaImageLoader nefunguje (known issue), mohli byste (moc prosim) pokud nekdo mate IE8 vyzkouset, zdali to leakuje jako test.htm, nebo ne?
_es
Profil
RobertVarga
Rátaš s možnosťou, že rýchlosť siete nemusí stačiť na tak časté načítavanie tak veľkého obrázka?
Skús kód upraviť:
var obr1 = document.getElementById("obrazek1");
obr1.onload = obr1.onerror = obr1.onabort = function(){this.hotovo = true;};
setInterval(function(){if(obr1.hotovo) obr1.hotovo = false, obr1.src = "sunset.jpg?rnd=" + (new Date).getTime();}, 2000);
RobertVarga
Profil *
Zajimavy, moc diky :-) Upraveno.

Ted uz jen najit nekoho, kdo by to na tom IE8 otestoval: test.htm (leakovalo mi 6MB kazdou druhou vterinu); a take testAIL.htm (leakuje/neleakuje?). V tom zapalu jsem to sem z prace zadal, ale domu k IE8 se dostanu az pozitri :-(
_es
Profil
RobertVarga
Vyššie uvedený kód som ešte upravil. Vlastnosť complete asi nie je až tak vhodná.
RobertVarga
Profil *
Upraveno, takze update:

IE8 memory leak (ve style je definovane width a height):
http://www.gamelot.cz/test.htm

Bez problemu (ve style neni definovane width a height):
http://www.gamelot.cz/testBez.htm

Vyuziti AlphaImageLoader (leakuje??):
http://www.gamelot.cz/testAIL.htm
_es
Profil
RobertVarga
V IE nezostáva zobrazený starý obrázok pred zobrazením nového, takže to bude treba asi takto:
var obr1 = document.getElementById("obrazek1"), i = new Image;
i.hotovo = true;
i.onload = i.onerror = i.onabort = function(){this.hotovo = true;};
setInterval(function(){if(i.hotovo) i.hotovo = false, obr1.src = i.src, i.src = "sunset.jpg?rnd=" + (new Date).getTime();}, 2000);
RobertVarga
Profil *
http://www.gamelot.cz/testHonza.htm

AlphaImageLoader nefunguje v IE8 :-(
RobertVarga
Profil *
Nakonec se mi povedlo IE8 nainstalovat na jeden server.

Bohuzel, na Windows Server 2003/32bit to NELEAKUJE ( http://www.gamelot.cz/test.htm ).

Zaroven jsem volal kamaradum kvuli testovani, a na Win7, WinVista a WinXP to LEAKUJE.

Vsichni stejne verze IE8. :-(
RobertVarga
Profil *
Tvuj novy script nefunguje.
_es
Profil
Opravené. Pre počiatočný efekt v IE bude asi lepšie v HTML kóde nenastaviť pre <img> src.
Chamurappi
Profil
Reaguji na RobertaVargu:
Koukám, že ti na tom microsoftím Technetu nikdo neodpovídá.
Řekl bych, že ses tam u nich zeptal na špatném místě. Lidé, kteří mají na starost skriptování všeobecně (tedy JS/VBS nejen na webu), s únikem paměti při překreslování zvětšovaného obrázku v Exploreru nic nezmůžou.
polom
Profil *
Tak jsem hledal články na téma memory leaks a nedalo mi to zkusit vlastní řešení. Akorád jsem u toho nepochopil jak RobertVarga mění obrázky takže jsem to udělal takto:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>JS memory leak</title>
    <meta http-equiv="content-type" content="text/html; charset=windows-1250" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="expires" content="-1" />
    <meta http-equiv="Cache-Control" control="no-store">
<script language="JavaScript" type="text/javascript">
function getRandomArbitary(min, max)   {   return Math.round(Math.random() * (max - min) + min);    } 

function zmenObraz(){
var obr = document.getElementById("obrazek1");
  function zmenit(){
 	obr.src = "pics/"+getRandomArbitary(1,8)+".jpg";
 	obr.title = obr.src;
  }
zmenObraz=null;
return zmenit;
}
</script>
</head>
<body onload="var zmenObr = zmenObraz(); setInterval(zmenObr, 2000)">
 <img src="pics/1.jpg" alt="Zmen img" id="obrazek1" />
</body>
</html>


Šlo mi o to zcela vypustit globální proměnné. Nevím jestli jste zkoušeli na vašem příkladu kolik vám to zabírá paměti, ale u mého příklad paměť IE mi lítá okolo 26 až 30MB pro 200-275KB obrázky. U FF byly rozdíly až 35MB což nechápu.

Jinak jsem si všiml, že u prvního příkladu od RobertVarga je špatně deklarace "vnitřní" funkce
funkce = function()

zavádí funkci do globálního scopu
místo
var funkce = function()

jako lokální proměnnou. Taky při každém volání se znovu deklaruje a spouští takže
funkce=null;
nemá žádný smysl
_es
Profil
polom:
takže funkce=null; nemá žádný smysl

IE vytvára objekty DOM pomocou objektov COM, s horším systémom zberania voľnej pamäti.
Takže potom niekedy aj takéto divné príkazy môžu mať zmysel.
Niečo je o tom na http://msdn.microsoft.com/en-us/library/Bb250448, keby niekto našiel niečo v češtine alebo slovenčine…
polom
Profil *
_es:
Paradoxně uvádíš zdroj ze kterého jsem čerpal :-) Právě že to nemá smysl, protože nepoužil lokální proměnnou, ale globální... Já ti nevím, čeho chtěl autor dosáhnout. Zadaný příklad myslím lze provést jedním řádkem bez globálních proměnných, ale kdyby chtěl použít argument, tak bych asi použil tu svou funkci, kde se nulluje ta rodičovská funkce. Tím, že nulluje vnitřní funkci, nějak nechápu k čemu... Protože on ji pak nelogicky znovu vytváří a zase nuluje. A ty tam vidíš nějaký zpětný odkaz? Element načítá do obr1 ale na ob1 nikde neodkazuje.
_es
Profil
polom:
Mne sa ten kód podrobne študovať nechcelo, len som chcel upozorniť na odlišnosti IE od iných prehliadačov, vzťahujúce sa k tejto téme. Tie tu doteraz spomenuté neboli.
polom
Profil *
_es:
len som chcel upozorniť na odlišnosti IE od iných prehliadačov
Jo za tu připomínku dík, já jsem zase chtěl ukázat na ty chyby které udělal v tom prvním kódu. Asi chtěl sestrojit uzávěru, ale moc to nevychytal.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: