Win2D 官方文章系列翻译 - 避免内存泄漏
本文为个人博客备份文章,原文地址:
http://validvoid.net/win2d-avoiding-memory-leaks/
在托管 XAML 应用中使用 Win2D 控件时,必须谨慎处理对象引用计数,以免控件不能被垃圾回收器回收。
内存泄漏的发生条件
- 你正在通过 C# 等 .Net 语言 (非原生 C++)使用 Win2D
- 你使用了以下任一 Win2D 控件:
- CanvasControl
- CanvasVirtualControl
- CanvasAnimatedControl
- CanvasSwapChainPanel
- 你订阅了 Win2D 控件的事件(如
Draw
,CreateResources
,SizeChanged
...) - 你的应用在多个 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 官方文章系列翻译 - 避免内存泄漏相关推荐
- Win2D 入门教程 VB 中文版 - 防止内存泄漏
避免内存泄漏 本文从微软官方文档翻译 http://microsoft.github.io/Win2D/html/RefCycles.htm 如果文档有问题,可以在 https://github.co ...
- Vue系列之常见内存泄漏定位与解决
JavaScript 有完善的内存处理机制,能自动进行垃圾回收,但是假如一个对象一直被引用,他的内存是无法得到释放的.如果项目运行过程中,内存占用越来越高,只增不减,没有峰值,就存在内存泄漏.多页应用 ...
- Android 如何做一次内存泄漏大排查
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/112335970 本文出自[赵彦军的博客] 文章目录 前言 把内存泄漏的地方找出来 ...
- Android内存泄漏就这样产生了
为什么80%的码农都做不了架构师?>>> 1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及 ...
- Android内存优化之内存泄漏
内存泄漏 内存泄漏一般有以下几种情况:单例.静态变量.Handler.匿名内部类.资源使用未关闭 单例导致的内存泄漏 单例的情况主要是因为单例的生命周期比较长,如果引用的一些资源(比如Context. ...
- Android内存泄漏的各种原因详解
转自:http://mobile.51cto.com/abased-406286.htm 1.资源对象没关闭造成的内存泄漏 描述: 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我 ...
- 内存泄漏分析框架LeakCanary的使用与原理解析
文章目录 1. 常见内存泄漏 1.1 "单例模式" 造成的内存泄漏 1.2 "静态实例" 造成内存泄漏 1.3 "Handler" 造成的内 ...
- 内存泄漏和内存溢出以及原因和解决方案
1.什么是内存泄漏? Java 中的内存泄漏是指应用程序不再需要的对象在 Java 虚拟机 (JVM) 中仍然存在的状态.通俗来讲就是生命周期长的对象持有生命周期短的对象,导致GC无法回收本该需要回收 ...
- Js内存泄漏情况解析
文章目录 一.内存泄漏 二.常见原因 1.意外的全局变量 2.未被清空的定时器 3.滥用闭包 4.未被销毁的事件监听 5.无效的Dom引用 一.内存泄漏 内存泄漏,指在JS中已经分配内存地址的对象 ...
最新文章
- 【AutoML】连续可微分架构如何用于网络结构搜索
- 2009年9月等考试题及答案51CTO站第一时间发布
- 谈谈为什么我们需要云原生架构?
- 前端职业规划 - 前端技术专家们的生死书
- 制作Camtasia 2020击键标记动画——保存及应用
- 开源 syslog 日志系统 scribe
- 外贸术语(FOB,CIF,CFR,FCA,CPT,CIP,EXW、FAS、DAF、DES、DEQ、DDU、DDP)
- ZlycerQan的 八云蓝(ran )
- Sencha Cmd 优化 Sencha Ext JS/7.5.12
- appium的安装+连接夜神模拟器控制app
- EarthSDK 项目开发使用说明
- 最新消息,青岛的农贸市场将迎来大变革
- 2022-2028中国有机蒙脱石市场现状研究分析与发展前景预测报告
- 【PTA】代码部分基础整理
- mac es安装踩坑日记
- Qt5学习 模仿qq音乐播放器样式(1)
- 机房如何防止雷电攻击?手把手教你
- 阿里云ECS进阶训练营Day1 搭建VuePress
- 国家发改委正式将「区块链」纳入新基建
- 全志A33学习笔记及问题汇总
热门文章
- 从指南针到北斗:中国导航系统促进世界互联互通
- 2019年深度学习的十大预测
- 广度深度都要,亚马逊是如何推动 Alexa 内生成长的?
- 重磅!Gartner公布2019年十大战略科技发展趋势
- 德扑 AI 之父解答 Libratus 的13个疑问:没有用到任何深度学习,DL 远非 AI 的全部
- 什么工作,未来可以走创业路线?
- 终于!朋友圈可以删除别人评论了……
- 如何把gcc编译工具使用到linux全局
- 【Android游戏开发二十七】讲解游戏开发与项目下的hdpi 、mdpi与ldpi资源文件夹以及游戏高清版本的设置...
- NSUserDefaults删除整个plist文件