许多文件请求后,Cordova-Angularjs App停止在iPad上

时间:2014-12-15 11:27:09

标签: ios angularjs ipad cordova

我正在尝试用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插件:设备,记录器和文件。

1 个答案:

答案 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调用有关,那么应用程序中的每个调用都会导致泄漏。