钛合金内存管理

3

我已经阅读了很多关于如何控制Titanium移动应用程序在Android平台上的内存泄漏的网页。

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

在每个视图中,都会创建一个事件侦听器来检查点击了哪个tableRow,然后创建相应的子菜单并将其动画显示在屏幕上。

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

目前,我正在检查主窗口,以查看窗口是否已动画显示在视图之外(然后在320像素宽的设备上,.left属性为320)。然后,我会将此视图从窗口中删除,并将代理设置为null,使用以下方法:

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工具包提供的内存使用情况?是否有一种方法可以获取所有全局变量或事件监听器?


你可以使用Dalvik工具包来分析由Titanium生成的Android项目,检查其构建文件夹。同时尝试使用removeEventListener - Josiah Hester
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;
    });
}
请注意,在上面的例子中,如果我已经将视图添加到要删除的“视图”中,我不需要逐个显式地删除它们。确保您将所有悬空引用设置为null。然后,当视图被移除和置空时,GC可以清理它及其所有子级。
这种做法会逐渐变得自然。但是,当您开始考虑它时,最好重复应用程序中的离散操作(转到一个屏幕,导航回到以前的屏幕,再次转到同一个屏幕,导航回去等),以找到您正在失去大部分内存的地方。然后修改代码以消除资源耗尽。
有时可能会很困难和令人沮丧,但请坚持下去,我相信您会想出解决方法!

1

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

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

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

记住,您可以注释掉大段的代码,以查看是否是罪魁祸首。例如,当我怀疑某个代码片段存在泄漏时,我会注释掉该代码并查看对象实例的数量是否按预期增加和下降。

我发现如果我关闭了一个窗口,只要正确声明了分配的对象,所有分配的对象最终都会被清理掉。我发现我的变量中有1-2个缺少了“var”关键字,因此我认为它们是在全局范围内声明的,因此我进行了清理。
我在Appcelerator的论坛上发布了求助帖子,以下是我的贴子: http://developer.appcelerator.com/question/148246/profiling-and-cleaning-up-objects 该帖子有几个建议,并提供了一个链接到Appcelerator的视频,介绍如何调试你的应用程序。

尽管这个答案非常有用,但是像这样的测试似乎在 Android 上并没有太大的帮助 - 只有当系统需要内存时,它才会释放对象。因此,你不能关闭一个窗口并期望内存立即被释放。 - LucasA

0

这样做是否也可行?在这种情况下,我设置了监听器,并将监听器附加到表格上。单击表格后,将删除侦听器,并使用create()方法创建一个新表格。 它以递归方式工作(create()函数在单击表格后调用自身),这让我感到怀疑。但是它应该会删除事件侦听器,从窗口中删除视图并将其代理设置为零吧?

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);
}

從這個例子很難判斷。最好的方法是將其帶到一些客觀地告訴您它是否正常工作的東西 - Xcode儀器。 (可能有一個Android版本可以為您提供相同的信息 - 存活和垃圾收集的視圖和代理數量 - 但我現在不是最新的。) - Dawson Toth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接