2014-07-18 15 views
13

Pracuję nad aplikacją angularjs, używając dyrektyw angularjs-nvd3 do renderowania wykresów.Jak uniknąć wycieków pamięci za pomocą dyrektyw angularjs-nvd3

Po sprawdzeniu w Narzędziach dla programistów w przeglądarce Chrome wykryłem wycieki pamięci powiązane z wykresami. Gdy użytkownik przegląda różne widoki zawierające wykresy, pamięć nigdy nie jest w pełni zwolniona.

ja już robi jakieś porządki na kontrolerach wykresy:

$scope.$on('$destroy', function() { 
    d3.select('#exampleId').remove(); 
    d3.select('#exampleId2').remove(); 
    ... 
}); 

A na razie routeChange:

myApp.run(function($rootScope, $templateCache) { 
    //try to clear unused objects to avoid huge memory usage 
    $rootScope.$on('$routeChangeStart', function(event, next, current) { 
    if (typeof(current) !== 'undefined'){ 
     //destroy all d3 svg graph 
     d3.selectAll('svg').remove(); 
     nv.charts = {}; 
     nv.graphs = []; 
     nv.logs = {}; 
    } 
    }); 
}); 

Kiedy usunąć wykresy z mojej aplikacji, wykorzystanie pamięci zawsze idzie z powrotem do wartości początkowej.

Z wykresu: with graph whithout: without

jest jakiś inny sposób, aby zwolnić pamięć generowanego przez te wykresy?

jsfiddle, aby zademonstrować problem.

+2

Nie mam odpowiedzi, ale jestem również chętny, aby znaleźć sposób na zniszczenie wykresów na zmianę stanu/trasy. Ten problem jest omawiany tutaj: https://github.com/novus/nvd3/pull/396 – dennis

+0

Witam! Którą wersję nvd3 używasz? – Artemis

+0

@Artemis v1.1.15-beta – Pierre

Odpowiedz

2

Możesz zapomnieć o usunięciu słuchaczy zmiany rozmiaru okna.

angularApp.run(function($rootScope) { 
    $rootScope.$on('$routeChangeStart', function(event, next, current) { 
    if (typeof(current) !== 'undefined'){ 
     //destroy d3 stuff 
     window.nv.charts = {}; 
     window.nv.graphs = []; 
     window.nv.logs = {}; 

     // and remove listeers for onresize. 
     window.onresize = null; 
    } 
    }); 
}); 

Możesz również spróbować usunąć cały element svg, ale nie wydaje się to najlepszym sposobem.

+0

'window.onresize = null;' jest dobrym punktem, działa dobrze na przykładzie jsfiddle. Jednak w przypadku bardziej złożonego wykresu wydaje się, że nadal występują wycieki pamięci powiązane z wykresami nvd3. Sądzę, że dostaniesz nagrodę, jeśli nie otrzymam żadnych innych odpowiedzi. – Pierre

+0

Możesz również spróbować bezpośrednio użyć api d3 - czasami możesz uzyskać wzrost wydajności. Nvd3 jest właśnie opakowaniem dla d3 apis. Możesz obejrzeć tutaj - https://github.com/d3/d3-plugins. – Artemis

+0

Tak, to już robię dla jakiegoś wykresu;) – Pierre

0

zalecam przenieść swój wykres do własnych dyrektyw, które posiadają dyrektyw nvd3 na ich szablonów i słuchać o każdej dyrektywy dla zakresu.

$destroy również niszczy element tego wydarzenia.

Kontrolery powinny pobrać dane i przypisać je do dyrektywy.
Być może zechcesz posłuchać instrukcji $routeChangeStart w dyrektywie, więc czyszczenie zostanie obudowane na części korzystającej z danych. W ten sposób unikniesz powielania kodu.
Używam tych technik do czyszczenia moich dyrektyw, które używają modałów, więc nie mam zduplikowanych zdarzeń słuchaczy ani identyfikatorów.

+1

Używam teraz własnych dyrektyw, bez nvd3 po prostu D3. W ten sposób dokładnie wiem, co niszczyć w zakresie. $ Destroy. Rozwiązałem 95% wycieku w ten sposób. – Pierre

2

Jest podobny problem na github: https://github.com/cmaurer/angularjs-nvd3-directives/issues/193

Jak wyjaśniono tam dodaje pracował lepiej:

$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) { 
angular.element(document.body.querySelectorAll('.nvd3')).remove(); 

To rozwiązuje przecieków pamięci SVG. Ale nadal istnieją pewne wycieki pamięci po stronie danych (Array).

+0

Dzięki za wejście, nie używam nvd3, ale to jest bardzo interesujące. Wygląda jak 'd3.selectAll ('svg'). Remove();' ale w sposób kanciasty. – Pierre

+1

nie. Miałem już d3.selectAll ('svg'). Remove(); który nie działał. Nawiasem mówiąc, łączę oba te kody (ty napisałeś i moje) podczas połączenia rozgłoszeniowego. – bugdayci

+0

Aby poinformować użytkownika d3, używam 'd3.select (" # "+ attrs.id) .remove();' w moich własnych dyrektywach dotyczących zdarzenia '$ destroy'. To działa dla mnie. Nadal występują przecieki, ale mniej niż wcześniej. – Pierre

Powiązane problemy