Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Wyciek pamięci (jQuery)
Forum PHP.pl > Forum > Po stronie przeglądarki > JavaScript
kamloo21
Hej
Mam problem z jquery , napisałem kilka animacji , wszystko ładnie działa lecz po pewnym czasie (jakieś 10min) drastycznie zwiększa się użycie pamięci które dochodzi do 1GB na 1 zakładke w Chrome.
Domyślam się że animacja jest źle zloopowana ale wydaję mi sie że jest OK. Próbowałem kilku różnych rzeczy

http://wytestuj.cba.pl/tyla/send.php Chodzi mi o tą animacje konkretnie (na reszcie strony jest inna więc nie zmieniajcie zakładki)

  1. $(document).ready(
  2. function animuj(){
  3. $("#loga").animate(
  4. { backgroundPosition: "+=2000" }, 19000 //animacja paska na dole
  5. ).animate(
  6. { backgroundPosition: "-=2000" }, 19000 //animacja paska na dole
  7. );
  8.  
  9. $("p.active").prev("p").css("border-bottom-color","#363732"); //zmiana koloru ramki nad .active
  10.  
  11. $("#menu p").hover( //animacja menu
  12. function(){
  13. $(this).prev().css("border-bottom-color","#363732");
  14. $(this).addClass("hover");
  15. },
  16. function(){
  17. if(!$(this).hasClass('active'))
  18. $(this).prev().css("border-bottom","#666 dotted 2px");
  19.  
  20. $(this).removeClass("hover");
  21. }
  22. );
  23.  
  24. setInterval(animuj,40000);
  25. }
  26. );
zegarek84
po pewnym czasie masz wieeele razy odpaloną funkcję animuj i cyklicznie w postępie lawinowym podpinany setInterval(animuj,40000) - w tym miejscu co jest wystarczył by setTimeOut... lub troszkę inaczej to zapisać...

ps. nie potrzebnie wiele razy podpinasz .hover... prędzej byś skożystał z .delegate (coś jak .live)

ps2. skoro elementy #loga i #menu sa w drzewie DOM po .ready to mógłbyś te elementy wyszukać i zapamiętać w jakiejś zmiennej by ich nie szukać stale po selektorach CSS

ps3. jeśli elementy #menu nie zmieniają sie dynamicznie to wystarczyło by raz podpiąć .hover...
kamloo21
Tzn .hover mam podpięte dokładnie 1 raz , chodzi ci o to żeby znajdował sie poza funkcją animuj , tak ?

Co do tych selektorów , to zapisać je przed .ready() czy w środku ? Bo wydaje mi się że mimo wszystko one i tak będą sie wyszukiwać na nowo

Zaraz spróbuję z tym setTimeOut i dam znać

Dzięki za nakierowanie smile.gif
zegarek84
To co Ty napisałeś już poprawniej powinno działać przy takim zapisie (minimalna modyfikacja tylko więc HOVER będzie przypisywany dodatkowo przy każdej animacji - tu też będzie minimalny wyciek pamięci ale większość by go pominęła...)
[JAVASCRIPT] pobierz, plaintext
  1. $(document).ready(
  2. function(){
  3. function animuj(){
  4. $("#loga").animate(
  5. {
  6. backgroundPosition: "+=2000"
  7. }, 19000 //animacja paska na dole
  8. ).animate(
  9. {
  10. backgroundPosition: "-=2000"
  11. }, 19000 //animacja paska na dole
  12. );
  13.  
  14. $("p.active").prev("p").css("border-bottom-color","#363732"); //zmiana koloru ramki nad .active
  15.  
  16. $("#menu p").hover( //animacja menu
  17. function(){
  18. $(this).prev().css("border-bottom-color","#363732");
  19. $(this).addClass("hover");
  20. },
  21. function(){
  22. if(!$(this).hasClass('active'))
  23. $(this).prev().css("border-bottom","#666 dotted 2px");
  24.  
  25. $(this).removeClass("hover");
  26. }
  27. );
  28.  
  29. }
  30. setInterval(animuj,40000);
  31. animuj();
  32. }
  33. );
[JAVASCRIPT] pobierz, plaintext

skoro hover wystarczy raz przypisać więc dla zobrazowania z zapamiętanym elementem do animacji kod można by zapisać w ten sposób (urzyta tutaj 1 zmienna globalna - można to inaczej zapisać...)
[JAVASCRIPT] pobierz, plaintext
  1. var jLoga;
  2. function animuj(){
  3. jLoga.animate(
  4. {
  5. backgroundPosition: "+=2000"
  6. }, 19000 //animacja paska na dole
  7. ).animate(
  8. {
  9. backgroundPosition: "-=2000"
  10. }, 19000 //animacja paska na dole
  11. );
  12.  
  13. $("p.active").prev("p").css("border-bottom-color","#363732"); //zmiana koloru ramki nad .active
  14. }
  15. $(document).ready(
  16. function start(){
  17. jLoga = $("#loga");
  18. $("#menu p").hover( //animacja menu
  19. function(){
  20. $(this).prev().css("border-bottom-color","#363732");
  21. $(this).addClass("hover");
  22. },
  23. function(){
  24. if(!$(this).hasClass('active'))
  25. $(this).prev().css("border-bottom","#666 dotted 2px");
  26.  
  27. $(this).removeClass("hover");
  28. }
  29. );
  30. setInterval(animuj,40000);
  31. animuj();
  32. }
  33. );
[JAVASCRIPT] pobierz, plaintext

bez zmiennej globalnej można by np. w ten sposób - sposobów jest wiele i nie chcę narzucać rzadnego stylu, urzyta jest tutaj tylko dodatkowa anonimowa funkcja
[JAVASCRIPT] pobierz, plaintext
  1. $(document).ready(
  2. (function(){
  3. var jLoga;
  4. function animuj(){
  5. jLoga.animate(
  6. {
  7. backgroundPosition: "+=2000"
  8. }, 19000 //animacja paska na dole
  9. ).animate(
  10. {
  11. backgroundPosition: "-=2000"
  12. }, 19000 //animacja paska na dole
  13. );
  14.  
  15. $("p.active").prev("p").css("border-bottom-color","#363732"); //zmiana koloru ramki nad .active
  16. }
  17. function start(){
  18. jLoga = $("#loga");
  19. $("#menu p").hover( //animacja menu
  20. function(){
  21. $(this).prev().css("border-bottom-color","#363732");
  22. $(this).addClass("hover");
  23. },
  24. function(){
  25. if(!$(this).hasClass('active'))
  26. $(this).prev().css("border-bottom","#666 dotted 2px");
  27.  
  28. $(this).removeClass("hover");
  29. }
  30. );
  31. setInterval(animuj,40000);
  32. animuj();
  33. }
  34. return start;
  35. })()
  36. );
[JAVASCRIPT] pobierz, plaintext

w tamtym miejscu gdzie wcześniej miałeś setInterwal prędzej pasowała funkcja setTimeout...

ps.
nie wiem czy p.active zmienia się dynamicznie czy nie więc nie buforowałem tych selektorów... ale jeszcze jeśli gdzieś zmieniasz klasę .active to można by zbuforować jakiś element nadrzędny nie zmieniający się z jakimś np. id i w jQuery skożystać z kontekstów, więc nie szukać tych elementów p.active w całym dokumencie HTML tylko podać kontekst - ale to już takie zagadnienia optymalizacyjne...
kamloo21
Poczytałem troche o setInterval i setTimeout i zastosowałem sie do twoich rad.
Sama zamiana z setInterval na setTimeout rozwiązała problem i teraz strona sie nie zawiesza i nie pobiera 1GB pamięci , lecz nadal bierze ~140MB co jest dużą liczbą
Myśle że drugie rozwiązanie które mi podesłałeś będzie OK, jak przerobie to napisze co i jak. Dzięki ! smile.gif


PS. W drugim rozwiązaniu jest var jLoga;
Czemu odrazu nie ustawiłeś wartości jLoga = $("#loga") ?
zegarek84
Cytat(kamloo21 @ 2.05.2013, 19:00:10 ) *
PS. W drugim rozwiązaniu jest var jLoga;
Czemu odrazu nie ustawiłeś wartości jLoga = $("#loga") ?

tylko to zależy, kiedy zaczyna się o tym myśleć ;p - a to dosyć ważne, gdyż jest to dostępne dopiero po documentready ;p, czyli jak cały DOM załadowany, po to z tej metody kożystałeś... ;p... trochę inaczej zapisane a to samo znaczące ;p - po prostu wcześniej tego elementu anie znajdziesz...
[JAVASCRIPT] pobierz, plaintext
  1. (function(){
  2. var jLoga;
  3. function animuj(){
  4. jLoga.animate(
  5. {
  6. backgroundPosition: "+=2000"
  7. }, 19000 //animacja paska na dole
  8. ).animate(
  9. {
  10. backgroundPosition: "-=2000"
  11. }, 19000 //animacja paska na dole
  12. );
  13.  
  14. $("p.active").prev("p").css("border-bottom-color","#363732"); //zmiana koloru ramki nad .active
  15. }
  16. function start(){
  17. jLoga = $("#loga");
  18. $("#menu p").hover( //animacja menu
  19. function(){
  20. $(this).prev().css("border-bottom-color","#363732");
  21. $(this).addClass("hover");
  22. },
  23. function(){
  24. if(!$(this).hasClass('active'))
  25. $(this).prev().css("border-bottom","#666 dotted 2px");
  26.  
  27. $(this).removeClass("hover");
  28. }
  29. );
  30. setInterval(animuj,40000);
  31. animuj();
  32. }
  33. $(document).ready(
  34. start
  35. );
  36. })();
[JAVASCRIPT] pobierz, plaintext

PrinceOfPersia
1. w Google Chrome jest profiler (z którego się dopiero uczę korzystać, w zasadzie dzięki temu wątkowi, zmotywowałem się i zacząłem się bawić (Ctrl + Shift + J, wybierz zakładkę Profiles, dalej "Take Heap Snapshot"). Może coś odkryjesz.

2. zainteresowałbym się animacjami CSS3 (@keyframes etc.) zamiast jQuery.animate (nie wiem czy to rozwiąże twój problem z pamięcią, bo problem może być gdzie indziej, ale spróbowac można)
zegarek84
podejrzałem dzisiaj kod na Twojej stronie i widzę, że zrobiłeś "misz masz..." - zwróć uwagę, że nie buforujesz wyszukiwanych elementów choć je przypisujesz do zmiennej gdyż masz przypisane do zmiennej wewnątrz funkcji... masz teraz 2 funkcje animuj o.O - oczywiście wywoływana jest ta z bliższym scope...
kamloo21
Na strone wrzuciłem twoja wersje a moja wersja jest w komentarzu , wczoraj potestowałem to wszystko i teraz pobór pamięci utrzymuje się w granicach 26MB nawet po kilku godzinach więc udało się smile.gif Dzięki.
Jeszcze troche popracuje nad tym i będzie miodzio

@edit

W Chromie jest lepsza opcja , jak wejdziesz w Timeline kliknij na dole Record i masz cały wykres zużycia pamięci , FPSów itd
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.