这是 Xamarin Forms 中的内存泄漏吗?

2024-02-19

我遇到了一个问题,页面对象一旦被导航离开,就不会被垃圾收集。我整理了一个非常基本的示例,演示了使用 NavigationPage 和 PushAsync 方法时出现的问题。该页面使用弱引用列表显示“活动”页面的数量:

public class AppNavigationPage
{
    private static List<WeakReference> pageRefs = new List<WeakReference>();

    public static Page GetMainPage()
    {
        return new NavigationPage(CreateWeakReferencedPage());
    }

    private static Page CreateWeakReferencedPage()
    {
        GC.Collect();
        var result = CreatePage();
        pageRefs.Add(new WeakReference(result));

        // Add a second unreferenced page to prove that the problem only exists
        // when pages are actually navigated to/from
        pageRefs.Add(new WeakReference(CreatePage()));
        GC.Collect();
        return result;
    }

    private static Page CreatePage()
    {
        var page = new ContentPage();
        var contents = new StackLayout();

        contents.Children.Add(
            new Button
            {
                Text = "Next Page",
                Command = new Command(() => page.Navigation.PushAsync(CreateWeakReferencedPage()))
            });
        contents.Children.Add(
            new Label
            {
                Text = string.Format(
                    "References alive at time of creation: {0}",
                    pageRefs.Count(p => p.IsAlive)),
                HorizontalOptions = LayoutOptions.CenterAndExpand
            });

        page.Content = contents;
        return page;
    }
}

单击“下一页”按钮时,将创建一个新页面,其中带有固定值标签,显示创建此页面时活动的页面引用数。每次单击按钮时,您都会明显看到这个数字增加 1。我的理解是,当您单击导航页面上的“后退”时,视图应该从堆栈中弹出并丢弃(允许它被 GC) 。但是,当我运行此测试代码时,它表明在我们返回后,此视图将保留在内存中。这可以通过多次单击“下一页”直到引用计数为 3 来证明。如果您然后单击“上一步”,然后单击“下一页”,我相信引用计数仍应为 3(表明旧页面在新页面之前已被 GC)创建了一个)但是新的引用计数现在是 4。

这似乎是 iOS 的 X-Forms 导航实现中的一个相当严重的错误(我还没有在其他平台上测试过这个错误),我的猜测是它在某种程度上与此处描述的强引用循环问题有关:http://developer.xamarin.com/guides/cross-platform/application_fundamentals/memory_perf_best_practices/ http://developer.xamarin.com/guides/cross-platform/application_fundamentals/memory_perf_best_practices/

有其他人遇到过这个问题和/或提出解决方案/解决方法吗?其他人会同意这是一个错误吗?

作为补充,我做了第二个不涉及 NavigationPage 的示例(因此必须使用 PushModalAsync 代替),并发现我遇到了同样的问题,因此这个问题看起来并不是 NavigationPage 导航所独有的。作为参考,该(非常相似)测试的代码如下:

public class AppModal
{
    private static List<WeakReference> pageRefs = new List<WeakReference>();

    public static Page GetMainPage()
    {
        return CreateWeakReferencedPage();
    }

    private static Page CreateWeakReferencedPage()
    {
        GC.Collect();
        var result = CreatePage();
        pageRefs.Add(new WeakReference(result));

        // Add a second unreferenced page to prove that the problem only exists
        // when pages are actually navigated to/from
        pageRefs.Add(new WeakReference(CreatePage()));
        GC.Collect();
        return result;
    }

    private static Page CreatePage()
    {
        var page = new ContentPage();
        var contents = new StackLayout();

        contents.Children.Add(
            new Button
            {
                Text = "Next Page",
                Command = new Command(() => page.Navigation.PushModalAsync(CreateWeakReferencedPage()))
            });
        contents.Children.Add(
            new Button
            {
                Text = "Close",
                Command = new Command(() => page.Navigation.PopModalAsync())
            });
        contents.Children.Add(
            new Label
            {
                Text = string.Format(
                    "References alive at time of creation: {0}",
                    pageRefs.Count(p => p.IsAlive)),
                HorizontalOptions = LayoutOptions.CenterAndExpand
            });

        page.Content = contents;
        return page;
    }
}

我认为您看到的是异步导航的副作用,而不是内存泄漏。您可以选择终结器并创建 MyPage(而不是 ContentPage)的实例,而不是 WeakReferences。

    public class MyPage: ContentPage
    {
        private static int count;

        public MyPage()
        {
            count++;
            Debug.WriteLine("Created total " + count);
        }
        ~MyPage()
        {
            count--;
            Debug.WriteLine("Finalizer, remaining " + count);
        }
    }

下一个技巧是添加延迟的 GC.Collect() 调用,例如:

    private static Page CreateWeakReferencedPage()
    {
        GC.Collect();
        var result = CreatePage();
        var ignore = DelayedGCAsync();
        return result;
    }

    private static async Task DelayedGCAsync()
    {
        await Task.Delay(2000);
        GC.Collect();
    }

您会注意到,实例在此延迟收集(输出窗口)内被垃圾收集。 根据 Xamarin GarbageCollector:我怀疑它有严重缺陷。到处都有一个小错误,但不是那么大。也就是说,处理 Android 中的垃圾收集特别棘手,因为有两个垃圾收集 - Dalvik 的和 Xamarin 的。不过那是另一回事了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这是 Xamarin Forms 中的内存泄漏吗? 的相关文章

随机推荐

  • 在 SQL Server 数据库中保存字体的最佳方法

    在知道可以从不同环境 Windows Linux 和语言 Java PHP Python C 访问该字体的情况下 在 SQL Server 数据库中插入字体的最佳方法是什么 我有一个例子 我应该从 C Winforms 应用程序插入字体并从
  • 模板函数查找

    考虑这段代码 include
  • 在 .h 文件中声明结构并在 .c 文件中实现

    这是我的 h 文件 struct MyString typedef struct MyString MyString 我想在 c 文件中声明其成员 我试过 typedef struct MyString char str pointer t
  • 如何缩短 Git Bash 提示符 (Windows)

    如何缩短我的 git bash 提示符 Malik LAPTOP 7R9912OI MINGW64 Desktop test 像这样的事情 Malik test 我在 Windows 上使用 git bash git 版本为 2 21 0
  • java中从arraylist中删除具有多个索引的多个元素

    我有两个List2 我将项目存储在一个列表中 在第二个列表中我存储 int 数字 我将其视为索引 我想从包含所有索引的项目列表中删除项目 ArrayList
  • R中多个变量的线图

    我有以下格式的输入数据 x y z 0 2 2 4 5 5 3 8 6 8 10 4 6 9 3 15 7 6 10 5 我如何在R中像Excel 如下所示 一样绘制xy散点图 至少有四种方法可以做到这一点 1 此处使用名为 df 的 水平
  • 获取没有函数参数的二叉树的高度

    import java util Scanner public class BinaryTree private int info private BinaryTree left private BinaryTree right priva
  • 在 dplyr 中使用字符串作为过滤器?

    有没有办法在 dplyr 中使用字符串变量作为过滤器参数 例如 filter iris Sepal Length gt 6 将被替换为 string lt Sepal Length gt 6 filter iris string 基本上 我
  • 管理中的 AbstractController::DoubleRenderError

    我正在从事疯狂商务工作 我正在尝试调整 active sale controller 中的几个操作 我有一些条件 如果条件失败 我将重定向到 返回 否则我将继续下一步 我现在面临的问题是我在同一个操作中使用了两次redirected to
  • 无法安装 Visual Studio 2013 更新 5 (RTM); Apache Cordova 工具

    我正在尝试安装 VS2013 更新 5 但它不会安装 因为它被阻止 我必须 通过控制面板卸载旧版本的 Visual Studio Tools for Apache Cordova 多设备混合应用程序 我已经按照要求卸载了它 尽管与 VS20
  • Node js Express 中的环境变量(.env)

    是否可以为所有不同的部署环境 例如开发 生产等 提供一个 env 文件 根据环境 需要加载相应的环境变量文件 是的 您可以使用dotenv https github com motdotla dotenv module例如 env DB H
  • 在没有 JavaScript 的情况下将 HTML 元素与父元素的中间对齐

    我想在元素中间放置一个 水平对齐很容易 当然垂直对齐也可以用JS来完成 但我确信用CSS有更好的方法 有什么窍门呢 附 我需要这个用于具有 HTML5 元素的应用程序 因此我不介意该解决方案是否仅适用于支持画布的浏览器和 IE 7 8 使用
  • 使用 Typescript 时如何更新 Next-auth 中会话回调中的会话类型

    我正在使用打字稿 我的 next auth tsx 文件如下所示 import NextAuth Awaitable Session User from next auth import GithubProvider from next a
  • 如何使用try catch语句抛出错误?

    Utility const readUserUtility id a gt const currentstore store getState const returnedArray currentstore users filter us
  • 使用多个跟踪侦听器

    我有 2 个 WCF 服务 它们是从单个 Windows 主机托管的 我使用跟踪侦听器将数据记录到应用程序日志中 我已将以下代码添加到配置文件中
  • 插入符号训练的公式和非公式结果不同

    我注意到在训练时使用插入符中的公式和非公式方法会产生不同的结果 此外 公式方法所需的时间几乎是非公式方法所需时间的 10 倍 这是预期的吗 gt z lt data table c1 sample 1 1000 1000 replace T
  • 在 TeamCity 中全局禁用 FxCop 错误

    好的 今天还有一个 FxCop 问题 我已经阅读了有关 IdentifiersShouldBeCasedCorrectly 规则的争论 以及它是否应该是 XML 或 Xml 嗯 我是一个 XML 人 并且我想保持这种状态 因此 我做not希
  • 使用集束搜索实现 seq2seq

    我现在正在实施seq2seq基于示例代码的模型tensorflow提供 我想得到一个top 5解码器进行强化学习的输出 然而 他们用注意力解码器实现了翻译模型 所以我应该实现波束搜索来获取top k结果 现在有一部分代码已实现 该代码被添加
  • 无内存屏障的乱序写入:数据争用的唯一可能原因?

    在经历的同时Java 并发实践 作者 Brian Goetz我遇到了以下行 当一个变量被多个线程读取时 就会发生数据竞争 并由至少一个线程写入 但读取和写入不是按发生之前排序 正确同步的程序之一是 没有数据竞争 正确同步的程序表现出顺序 一
  • 这是 Xamarin Forms 中的内存泄漏吗?

    我遇到了一个问题 页面对象一旦被导航离开 就不会被垃圾收集 我整理了一个非常基本的示例 演示了使用 NavigationPage 和 PushAsync 方法时出现的问题 该页面使用弱引用列表显示 活动 页面的数量 public class