3

我已经阅读了很多讨论如何在基于 Titanium 的 Android 移动应用程序中控制内存泄漏的网页。

我的情况是我正在构建一个应用程序,该应用程序使用用户可以在其中导航的多个级别的列表(实际上这些是 tableViews)。它使用一个窗口,当用户选择一个列表项时,会创建一个从右到左动画的新视图。我选择了这个选项,因为似乎不可能创建一个从右到左滑入所有平台的新窗口。

在每个视图中,都会创建一个 eventListener 来检查单击了哪个 tableRow,然后创建相应的子菜单并将其动画到屏幕中。

我注意到每次单击视图后内存使用量都在稳步增长,但我似乎无法确定内存泄漏的位置。

目前我正在检查主窗口以查看窗口是否已被动画化(然后 .left 属性在 320px 宽的设备上为 320)。然后我从窗口中删除这个视图,并将代理设置为空,使用:

for ( i = 0; i < win.children.length; i++) {
    if ( (win.children[i] != null) && (win.children[i].left == 320) ) {
        win.remove(win.children[i]);
        win.children[i] = null;
    }
}

不过,它仍在增加内存使用量。这可能是因为每个新视图都包含一个表和一个事件侦听器,使用的函数包含:

var sub_table = Ti.UI.createTableView({top:'50dp',separatorColor: rowSeparatorColor});  
sub_table.setData(data);
sub_table.addEventListener('click', function(e) {
    create(e.rowData.data);
}); 
new_view.add(my_navbar);
new_view.add(sub_table);
return new_view;

我必须单独删除它们还是在视图被破坏时它们被破坏?我必须手动删除它们,我该怎么做?

在更一般的说明中,我不知道如何确定内存使用的原因。有没有办法在某个时间获取内存中的所有对象和/或变量?有没有办法深入了解 Dalvik 工具包提供的内存使用情况?有没有获取所有全局变量或事件监听器的方法?

4

3 回答 3

2

Titanium 应用程序中最常见的内存泄漏与保持变量引用有关。如果您在上下文中有一个上下文,则外部上下文的变量将被保留直到无效。如下所示。这可以在 Apple 的“Instruments”中通过过滤 TiUI 并观察视图数量和视图代理的增加来轻松观察到(如果您删除下面的所有“= null”行)。

var win = Ti.UI.createWindow();
win.open();

setInterval(function () {
    var view = Ti.UI.createView({
        backgroundColor: 'red',
        width: 300, height: 300,
        top: 100, left: 100
    });
    win.add(view);

    setTimeout(function () {
        fadeAwayAndRemove(view, win);
        view = null;
    }, 1000);
}, 2000);

function fadeAwayAndRemove(view, container) {
    var animation = {
        opacity: 0,
        duration: 300,
        transform: Ti.UI.create2DMatrix().scale(0.9, 0.9)
    };
    view.animate(animation, function () {
        container.remove(view);
        view = container = animation = null;
    });
}

另请注意,在上面的示例中,如果我向要删除的“视图”添加了视图,我不需要一次一个地显式删除它们。确保您取消对它们的所有挥之不去的引用。然后,当视图被删除并无效时,GC 可以清理它,以及它的所有子视图。

这种做法将开始成为你的第二天性。但是当您第一次开始考虑它时,最好在您的应用程序中重复离散操作(转到一个屏幕,导航回前一个屏幕,转到同一屏幕,返回等等)以找到你失去记忆最多的地方。然后处理代码以消除流失。

有时可能会很艰难和令人沮丧,但坚持下去,我知道你会解决的!

于 2013-03-06T03:32:17.043 回答
1

我没有使用过 Android 内存管理器,只有 Apple Instruments 应用程序。

首先是看你的应用程序,而不是作为一个整体。我逐行检查了主窗口的代码,确保我消除了任何已知的内存问题。我能够在我的主窗口上获得对象的基线数量,并使用它与我的应用程序中的其他窗口进行比较。然后,我将在这些窗口之间转换并解决所有内存问题,期望看到我分配的对象数量每次都返回到我的基线。

例如,如果我打开我的主窗口,我希望分配 2 个按钮和 2 个标签。我转换到下一个窗口,它有 2 个按钮和 2 个标签,我希望看到这些对象的数量跳到 4 和 4。然后我回到我的主窗口并关闭另一个窗口,我希望看到 2额外的按钮和标签最终会被清理干净。这不是即时的,所以我刷新或观察以确保它们消失。

请记住,您可以注释掉大部分代码,看看它是否是罪魁祸首。例如,当我怀疑一段代码中存在泄漏时,我会注释掉该代码并查看对象实例的数量是否按预期增加和减少。

我发现如果我关闭一个窗口,如果我正确声明了所有分配的对象,它们最终都会被清理掉。我发现我的变量的 1-2 个示例缺少 'var' 关键字,所以我相信它们是在全局范围内声明的,所以我清理了它。

我在 Appcelerator 的论坛上发帖寻求帮助,这是我的帖子:http: //developer.appcelerator.com/question/148246/profiling-and-cleaning-up-objects

这篇文章有一些建议以及 Appcelerator 的视频链接,该视频讨论了调试您的应用程序。

于 2013-03-07T20:09:02.277 回答
0

像这样的东西也会起作用吗?在这种情况下,我设置了侦听器,并将侦听器附加到表中。点击表后,监听器被移除,并使用 create() 方法创建一个新表。它有点递归地工作(create() 函数在单击表后调用自身),这让我感到怀疑。但它“应该”删除 eventListener,从窗口中删除视图并将其代理设置为零?

function create(i) {
    var listener = function(e) {
        win.removeEventListener('click', listener);
        win.remove(clickedview);
        clickedview = null;
        create(e.rowData.data);
    }
    var sub_table = Ti.UI.createTableView({top:'50dp',separatorColor: rowSeparatorColor});  
    sub_table.setData(data);
    sub_table.addEventListener('click', listener);
    new_view = populateView(i);
    new_view.add(sub_table);
}
于 2013-03-06T16:48:15.323 回答