【问题标题】:Mono for Android - OutOfMemoryError适用于 Android 的 Mono - OutOfMemoryError
【发布时间】:2011-09-07 09:16:21
【问题描述】:

我在我的 Mono for Android 应用程序中发现内存泄漏时遇到问题。我相信我正在遵循稍后概述的所有最佳实践,但在活动的一致、可重复的运行次数后,我不断收到 OutOfMemoryError。

在模拟器上使用ddms 可以看到,每次ViewFlipper 翻到下一页时,我的应用程序都会消耗大约200 个额外的“数据对象”和大约30kB 的内存。我们也在消耗其他资源,但速度要低得多。

我使用ViewFlipper 有点不合常规;它只向一个方向翻转,并去掉已经显示的Views:

while (flipper.ChildCount > 2)
{
    flipper.RemoveViewAt(0);
}

我非常注意Dispose() 对我们使用过的任何Views 的任何引用,例如described in this blog post。我对所有 UI 组件都使用using 虔诚地使用(自动Dispose() 范围末尾的对象):

using (TextView questionView = header.FindViewById<TextView>(Resource.Id.question))
{
    questionView.Text = question.Text;
}

这似乎对内存泄漏没有任何影响。每当我加载 Bitmaps(通常是 PNG 文件,大小小于 20kB)时,我都会使用相同的模式,我经常这样做。

更新:我使用扩展方法加载位图:

public static Bitmap BitmapFromAsset(this Context context, String asset)
{
    Bitmap bitmap;
    using (Stream stream = context.Assets.Open(asset))
    {
        bitmap = BitmapFactory.DecodeStream(stream);
        stream.Close();
    }
    return bitmap;
}

然后像这样使用位图:

using (Bitmap b = this.BitmapFromAsset(path))
{
    imageView.SetImageBitmap(b);
}

更新:正如 Aranda 在下面建议的那样,我使用委托,所以这是我代码中的常见模式:

using (View button = FindViewById(Resource.Id.button))
{
    button.Click += delegate
    {
        // do something
    };
}

更改此设置以便在删除 View 时删除处理程序对泄漏没有影响。

更新Bug posted with Xamarin with example project.

【问题讨论】:

    标签: c# android xamarin.android


    【解决方案1】:

    我有一个稍微相似的问题,而且很难找到(虽然在 WP7 上,但它仍然是相关的,因为它都是 .Net)。原来我已经从另一个没有超出范围的类将一些代表附加到我的 GameScreen 类。确保您正在执行 -= 任何附加的事件和委托,以及丢失对视图实例的引用。

    【讨论】:

    • 是的,我正在使用委托附加到不同的Views。所以我必须删除所有使用委托的事件处理程序,还是所有事件处理程序?假设你有这个:using (Button b = FindViewById&lt;Button&gt;(Resource.Id.button)) { b.Click += delegate (object s, EventArgs e) { /* code */ }; },你会在哪里移除代表?
    • 即使从等式中删除 Click 处理程序,我仍然会以与上述相同的方式泄漏内存。
    • 有趣。您的特定示例不会导致它泄漏,因为委托是一个匿名方法,并且将在视图实例本身的范围内。我想我也没有很好地解释自己。我的泄漏是因为我的 GameScreen 已将其中一个方法附加到我的 Engine 类中的事件(或委托)。引擎仍然通过附加事件持有对 GameScreen 类的引用。不一定与您的泄漏有关:(
    • 匿名委托仍然是(编译器生成的)方法。 o.E += (sender, e) =&gt; ...o.E += MethodName; 没有什么不同,前者仍然可以像后者一样保持 o 活着。
    • 好点jonp。我也错了,代表不会(在这种情况下)在 Button 视图的范围内。 @Vegard,你有没有运气找到泄漏?也许您需要在视图超出范围后显式处理位图?我知道您将它们放在using 块中,但也许 imageViews 本身会获取需要处理的副本?
    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    相关资源
    最近更新 更多