我正在尝试用Cordova和AngularJs编写一个iPad应用程序,它在启动时自动更新。因此,当应用程序过期时,我正在复制许多文件(js,css,images,...)。
大约400个文件后iPad-App冻结,延迟事件不再处理。我已经对我的应用程序进行了条带化并且来到了这个测试应用程序,它基本上只是连续10000次启动文件系统:
<!-- language: lang-js -->
angular.module('tablet', []).controller('StartCtrl', ['$scope', '$http', '$q',
function($scope, $http, $q) {
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
console.log('deviceready');
testFileSystem($q);
}
}
]);
function testFileSystem($q) {
var defer = $q.defer();
var chain = defer.promise;
defer.resolve();
// chaining 10000 init filesystem requests
for (var i = 0; i < 10000; i++) {
chain = chain.then(startInitFileSystem($q, i));
}
}
function startInitFileSystem($q, i) {
return function() {
return initFileSystem($q, i);
}
}
function initFileSystem($q, i) {
console.log('Init FileSystem: ' + i);
var defer = $q.defer();
window.requestFileSystem(PERSISTENT, 1024 * 1024 * 1024, function(fs) {
fileSystem = fs;
defer.resolve();
}, function() {
console.log("Init FileSystem failed");
defer.reject();
});
return defer.promise;
}
在997个请求之后,应用程序停止不再触发延迟事件。调试angularjs延迟对象时,我可以将问题缩小到方法:
<!-- language: lang-js -->
self.defer = function(fn, delay) {
var timeoutId;
outstandingRequestCount++;
try {
timeoutId = setTimeout(function() {
delete pendingDeferIds[timeoutId];
completeOutstandingRequest(fn);
}, delay || 0);
} catch (e) {
console.log(e.message);
}
pendingDeferIds[timeoutId] = true;
return timeoutId;
};
调用“setTimeout”,但在发生错误时不会触发。
这可能是某种内存泄漏吗?令人惊讶的是,如果您不使用角度延迟,它会起作用。有没有办法在解决后清理延迟?
我正在使用cordova插件:设备,记录器和文件。
答案 0 :(得分:0)
我有同样的问题。问题是您的内存正在运行,因为iOS设备上的setTimeout会发生泄漏。
您可以使用仪器和运行分配工具来验证这一点。在真实设备上运行您的示例并连接到该进程。连接后运行示例。你应该看到一个不断增长的分配图。当你重新实现你的例子而不使用任何setTimeout调用时,垃圾收集器正在清除它应该的一切。请注意垃圾收集有点懒,只有在分配了一定量的内存后才开始。所以你需要重新运行你的代码。
创建测试cordova项目时,我的示例代码添加到app对象:
run: function () {
function error(err) {
alert(err);
}
window.requestFileSystem(window.PERSISTENT, 0, function (fs) {
function tick(i) {
return function () {
if (i > 1000) return;
fs.root.getDirectory(String(i), { create: true }, function () {
setTimeout(next(i + 1), 0); // Removing setTimeout solves the memory leak
}, error);
};
}
tick(0)();
}, error);
}
请注意,即使函数已经完成处理,内存分配也会停留,没有setTimeout,内存在进程完成后会被垃圾回收。我目前不知道为什么会这样,但如果它真的与setTimeout调用有关,那么应用程序中的每个调用都会导致泄漏。