本文为个人博客备份文章,原文地址:

http://validvoid.net/win2d-avoiding-memory-leaks/

在托管 XAML 应用中使用 Win2D 控件时,必须谨慎处理对象引用计数,以免控件不能被垃圾回收器回收。

内存泄漏的发生条件

  • 你正在通过 C# 等 .Net 语言 (非原生 C++)使用 Win2D
  • 你使用了以下任一 Win2D 控件:
    • CanvasControl
    • CanvasVirtualControl
    • CanvasAnimatedControl
    • CanvasSwapChainPanel
  • 你订阅了 Win2D 控件的事件(如 DrawCreateResourcesSizeChanged...)
  • 你的应用在多个 XAML 页面中前进后退进行导航

如果以上情况全部满足,那么一个引用计数循环会阻止垃圾回收器回收 Win2D 控件。 在应用每次导航到一个新页面时,新的 Win2D 资源都会进行分配,而老资源则一直未被释放,从而造成内存泄漏。要避免这一情况,你必须手动添加代码打破引用计数循环。

如何修复

要打破引用计数循环以便使也页面能够被垃圾回收,你需要:

  • 订阅包含 Win2D 控件的 XAML 页面的 Unloaded 事件。
  • 在 Unloaded 事件的处理逻辑中,调用 Win2D 控件的 RemoveFromVisualTree 方法。
  • 在 Unloaded 事件的处理逻辑中,(通过将控件实例设为 null)释放任何对 Win2D 控件的直接引用。

示例代码:

void page_Unloaded(object sender, RoutedEventArgs e)
{this.canvas.RemoveFromVisualTree();this.canvas = null;
}

完整示例可以参见示例项目中的 demo 页面。

测试循环泄露

要测试你的应用是否正确打破了引用计数循环,可以在包含 Win2D 控件的页面里添加析构函数:

~MyPage()
{System.Diagnostics.Debug.WriteLine("~" + GetType().Name);
}

在应用的 App 构造函数中添加一个定时器以使垃圾回收定期执行:

var gcTimer = new DispatcherTimer();
gcTimer.Tick += (sender, e) => { GC.Collect(); };
gcTimer.Interval = TimeSpan.FromSeconds(1);
gcTimer.Start();

之后可启动应用进行调试,导航到页面,再导航到其它页面。如果全部引用循环被正确打破,一两秒内你就能在 Visual Studio 的输出面板看到 Debug.WriteLine 输出的信息。

注意

调用 GC.Collect 方法具有破坏性,会降低性能。因此一旦你完成内存泄漏测试,请务必移除此测试代码。

关键细节

当对象 A 引用了对象 B,同时对象 B 也引用了对象 A时,一个引用循环就会发生。当对象 A 引用对象 B, 对象B 引用对象 C,而对象C 引用对象A 等情况亦然。

当订阅一个 XAML 控件的事件时,这种引用循环不可避免:

  • XAML 页面承载了全部其所包含控件的引用
  • 控件承载了所有订阅其事件委托的引用
  • 每个委托承载了其目标实例的引用
  • 每个事件处理程序都是 XAML 页面类的实例方法,所以他们的目标实例又指向回 XAML 页面从而形成一个引用循环

如果以上引用过程中的所有对象都是 .Net 实现的,则引用循环并不会成问题。因为 .Net 能够自动进行垃圾回收,即便对象形成了引用循环,垃圾回收算法也能够识别并回收它们。

不同于 .Net, C++ 通过引用计数管理内存,它不能自动探测并回收对象引用循环。尽管有此限制, C++ 应用使用 Win2D 是没有问题的。因为 C++ 的事件处理程序默认承载对象实例的弱引用而非强引用。 因此页面引用控件,控件引用事件处理委托,而委托并没有引用回页面,因此不会产生循环。

而当一个 .Net 应用使用 Win2D 这类 C++ WinRT 组件时问题就出现了:

  • XAML 页面是应用的一部分,因此使用垃圾回收机制
  • Win2D 控件是由 C++ 实现的,因此使用引用计数机制
  • 事件处理委托是应用的一部分,因此使用垃圾回收机制并承载对目标示例的强引用

一个引用循环由此产生,而没有使用 .Net 垃圾回收机制的 Win2D 对象也参与了其中。 这意味着垃圾回收器无法查看整个引用链,因而它也无法探测和回收对象。当这一情况发生时,则必须通过显式打破引用循环来解决问题。一个方法是释放所有页面对控件的引用(如上文推荐那样);另外也可以找到所有可能指向回页面的事件处理委托,释放掉控件对这些委托的引用(在页面的 Unloaded 事件中解除所有事件处理的订阅)。

转载于:https://www.cnblogs.com/validvoid/p/win2d-avoiding-memory-leaks.html

Win2D 官方文章系列翻译 - 避免内存泄漏相关推荐

  1. Win2D 入门教程 VB 中文版 - 防止内存泄漏

    避免内存泄漏 本文从微软官方文档翻译 http://microsoft.github.io/Win2D/html/RefCycles.htm 如果文档有问题,可以在 https://github.co ...

  2. Vue系列之常见内存泄漏定位与解决

    JavaScript 有完善的内存处理机制,能自动进行垃圾回收,但是假如一个对象一直被引用,他的内存是无法得到释放的.如果项目运行过程中,内存占用越来越高,只增不减,没有峰值,就存在内存泄漏.多页应用 ...

  3. Android 如何做一次内存泄漏大排查

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/112335970 本文出自[赵彦军的博客] 文章目录 前言 把内存泄漏的地方找出来 ...

  4. Android内存泄漏就这样产生了

    为什么80%的码农都做不了架构师?>>>    1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及 ...

  5. Android内存优化之内存泄漏

    内存泄漏 内存泄漏一般有以下几种情况:单例.静态变量.Handler.匿名内部类.资源使用未关闭 单例导致的内存泄漏 单例的情况主要是因为单例的生命周期比较长,如果引用的一些资源(比如Context. ...

  6. Android内存泄漏的各种原因详解

    转自:http://mobile.51cto.com/abased-406286.htm 1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我 ...

  7. 内存泄漏分析框架LeakCanary的使用与原理解析

    文章目录 1. 常见内存泄漏 1.1 "单例模式" 造成的内存泄漏 1.2 "静态实例" 造成内存泄漏 1.3 "Handler" 造成的内 ...

  8. 内存泄漏和内存溢出以及原因和解决方案

    1.什么是内存泄漏? Java 中的内存泄漏是指应用程序不再需要的对象在 Java 虚拟机 (JVM) 中仍然存在的状态.通俗来讲就是生命周期长的对象持有生命周期短的对象,导致GC无法回收本该需要回收 ...

  9. Js内存泄漏情况解析

    文章目录 一.内存泄漏 二.常见原因 1.意外的全局变量 2.未被清空的定时器 3.滥用闭包 4.未被销毁的事件监听 5.无效的Dom引用 一.内存泄漏   内存泄漏,指在JS中已经分配内存地址的对象 ...

最新文章

  1. 【AutoML】连续可微分架构如何用于网络结构搜索
  2. 2009年9月等考试题及答案51CTO站第一时间发布
  3. 谈谈为什么我们需要云原生架构?
  4. 前端职业规划 - 前端技术专家们的生死书
  5. 制作Camtasia 2020击键标记动画——保存及应用
  6. 开源 syslog 日志系统 scribe
  7. 外贸术语(FOB,CIF,CFR,FCA,CPT,CIP,EXW、FAS、DAF、DES、DEQ、DDU、DDP)
  8. ZlycerQan的 八云蓝(ran )
  9. Sencha Cmd 优化 Sencha Ext JS/7.5.12
  10. appium的安装+连接夜神模拟器控制app
  11. EarthSDK 项目开发使用说明
  12. 最新消息,青岛的农贸市场将迎来大变革
  13. 2022-2028中国有机蒙脱石市场现状研究分析与发展前景预测报告
  14. 【PTA】代码部分基础整理
  15. mac es安装踩坑日记
  16. Qt5学习 模仿qq音乐播放器样式(1)
  17. 机房如何防止雷电攻击?手把手教你
  18. 阿里云ECS进阶训练营Day1 搭建VuePress
  19. 国家发改委正式将「区块链」纳入新基建
  20. 全志A33学习笔记及问题汇总

热门文章

  1. 从指南针到北斗:中国导航系统促进世界互联互通
  2. 2019年深度学习的十大预测
  3. 广度深度都要,亚马逊是如何推动 Alexa 内生成长的?
  4. 重磅!Gartner公布2019年十大战略科技发展趋势
  5. 德扑 AI 之父解答 Libratus 的13个疑问:没有用到任何深度学习,DL 远非 AI 的全部
  6. 什么工作,未来可以走创业路线?
  7. 终于!朋友圈可以删除别人评论了……
  8. 如何把gcc编译工具使用到linux全局
  9. 【Android游戏开发二十七】讲解游戏开发与项目下的hdpi 、mdpi与ldpi资源文件夹以及游戏高清版本的设置...
  10. NSUserDefaults删除整个plist文件