我们在AngularJS应用中遇到内存泄漏问题,同时在应用的不同部分之间切换。我们一直在努力寻找根本原因。
我们的应用程序中有一个主控制器。该主控制器包含另一个子控制器。该子控制器有两个部分。在任何时候,都会显示两个部分中的一个。第一部分有一些带按钮的html。单击此按钮时,它会切换到第二部分。我们使用jquery在两个不同的部分之间切换(我知道我们不应该混合jquery& angularjs,但它的长篇故事:-()
现在第二部分有 ui-view 。带有控制器的另一个视图在此ui视图中加载。此视图包含一个按钮(切换到第一部分)和另一个子 ui-view 。子UI视图加载了控制器。它使用ng-repeat在UI中填充数组。
当我们从第一部分切换到第二部分时,我们将$ state.go称为重新加载父级&第二节中的孩子ui-view。
每次使用$ state.go加载第二部分时都会发生内存泄漏。
以下是与应用代码类似的示例代码。实际的应用程序要复杂得多。但是可以使用下面的代码模拟内存泄漏情况。
<body ng-app="testApp">
<div ng-controller="MainCtrl">
<div ng-controller="SubCtrl">
<div id="Section1">
<h1> {{title}}</h1>
<button ng-click="SwitchToSection2()">Switch to Section 2</button>
</div>
<div id="Section2" style="display:none;">
<div ui-view="section2view"></div>
</div>
</div>
</div>
var app = angular.module('testApp', ['ui.router'])
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state("section2", {
views: {
'section2view': { templateUrl: 'section2-template.html' }
}
})
.state("section2.child", {
templateUrl: 'section2child-template.html',
params: { p1: "test" }
})
}]);
app.controller('MainCtrl', function($scope){
});
app.controller('SubCtrl', function($scope, $state){
$scope.title = "This is section 1";
$scope.SwitchToSection2 = function(){
$("#Section2").show();
$("#Section1").hide();
$state.go('section2.child', { p1: "test"}, { location: false, reload: true });
}
});
app.controller('Section2Controller', function($scope, $state){
$scope.SwitchToSection1 = function(){
$("#Section1").show();
$("#Section2").hide();
}
});
app.controller('Section2ChildCtrl', function($scope, $state){
$scope.itemArray = [];
for (var i = 0; i < 1000;i++) {
$scope.itemArray.push({
prop1: "Property 1",
prop2: "Property 2",
prop3: "Property 3",
});
}
});
内存泄漏
我正在使用Chrome开发者时间轴工具来识别泄漏。下面截图是在两个部分之间切换10次之后拍摄的。每次进入第2节,内存大小都会增加。内存不是GC。您还可以看到节点数逐渐增加。我还使用3 snapshot profile technique来查找分离的节点以及保留它的内容。但除了angularjs引用dom之外,它没有提供任何有用的信息。
如果有人能够指出正确的方向,那将会很有帮助。对不起,很长的帖子。谢谢。
答案 0 :(得分:1)
我无法使用您提供的说明书和说明重现泄漏。我已多次尝试过,但我发现任何泄漏事件都没有发生。
我已更改为:http://plnkr.co/edit/TtrbV9929H2ymaboFTNJ?p=preview这是代码:
var app = angular.module('testApp', ['ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state("section2", {
views: {
'section2view': { templateUrl: 'section2-template.html' }
}
})
.state("section2.child", {
templateUrl: 'section2child-template.html',
params: { p1: "test" }
})
}]);
app.controller('MainCtrl', function($scope){
console.log('Main controller instantiated');
$scope.$on('$destroy', function() {
console.log('Main controller has been destroyed');
});
});
app.controller('SubCtrl', function($scope, $state){
console.log('Sub controller instantiated');
$scope.$on('$destroy', function() {
console.log('Sub controller has been destroyed');
});
$scope.title = "This is section 1";
$scope.SwitchToSection2 = function(){
$("#Section2").show();
$("#Section1").hide();
$state.go('section2.child', { p1: "test"}, { location: false, reload: true });
}
});
app.controller('Section2Controller', function($scope, $state){
console.log('Section2 controller instantiated');
$scope.$on('$destroy', function() {
console.log('Section2 controller has been destroyed');
});
$scope.SwitchToSection1 = function(){
$("#Section1").show();
$("#Section2").hide();
}
});
app.controller('Section2ChildCtrl', function($scope, $state){
$scope.itemArray = [];
console.log($scope.itemArray.length);
for (var i = 0; i < 1000; i++) {
$scope.itemArray.push({
prop1: "Property 1",
prop2: "Property 2",
prop3: "Property 3"
});
}
console.log('Section2 Child Ctrl controller instantiated');
$scope.$on('$destroy', function() {
console.log('Section2 Child Ctrl controller has been destroyed');
});
});
因此,如果切换,您可以看到控制器正在被正确创建和销毁。晚了,但是没错。
我已经使用记录的分配来查看内存使用是否会超时增加。我重复各州之间的变化,比如一个疯狂的疯子,记忆力的使用并没有随着时间的推移而增加:
现在,如果我们看到时间表:
你可以看到同样的事情。垃圾收集最终会开始,并且可能会产生一些开销,导致如此多的节点被创建和销毁,但浏览器会自行恢复。
现在,如果您的应用程序中的情况不同,我只能认为是因为Section2控制器和子控制器在切换到第1节时不会死,因为您可能将这些控制器中的东西存储到作用域链中也许是泄漏的东西。但这只是我无法想象的事情,因为我还没有看到代码。
值得一提的是,我已经在OSX 10.11.1上的最新Chrome(46.0.2490.86)中对此进行了测试。结果可能因其他浏览器和/或操作系统而异,但如果是这样的话,罪魁祸首可能是浏览器本身。除了混合jQuery和Angular之外,它本身只是丑陋但不坏,我无法看到任何可能使提供的代码发生泄漏的事情。
答案 1 :(得分:-2)
你说这是一个很长的故事,你正在使用jQuery,但你没有详细说明......在我看来,在你给出的场景中,根本不需要使用它。我建议更新你的代码以使用角度功能,看看你是否有同样的问题。它的要点如下,或根据您的代码查看this updated Plunker。
在MainCtrl中设置两种状态和方法来控制它们:
app.controller('MainCtrl', function($scope){
$scope.sectionOneShown = true;
$scope.sectionTwoShown = false;
$scope.changeSection = function() {
console.log('changing');
$scope.sectionOneShown = !$scope.sectionOneShown;
$scope.sectionTwoShown = !$scope.sectionTwoShown;
};
});
相应地更新HTML模板:
<div ng-controller="MainCtrl">
<div ng-controller="SubCtrl">
<div id="Section1" ng-show="sectionOneShown">
<h1> {{title}}</h1>
<button ng-click="switchView()">Switch to Section 2</button>
</div>
<div id="Section2" ng-show="sectionTwoShown">
<div ui-view="section2view"></div>
</div>
</div>
</div>
从子控制器调用相同的方法来交换视图:
<div>
<div style="background-color:grey;padding:10px;" >
<h1>This is section 2</h1>
<button ng-click="switchView()" style="margin-left:200px;">Switch To Section 1</button>
<div ui-view></div>
</div>
</div>