DevExpress 的LayoutControl控件导致资源无法释放的问题处理
现象记录
- 前段时间同事发现我们的软件在加载指定的插件界面后,关闭后插件的界面资源不能释放, 资源管理器中不管内存,还是GDI对象等相关资源都不会下降。
问题代码
- 问题的代码大概如下。
public void LoadPluginUI(string pluginID)
{
this.Control.Clear();
Control ctl = GetPluginUI(pluginID);// ctl是我们插件的用户控件
this.Control.Add(ctl);
}
原因与解决方案
原因分析
解决问题的思路主要还是上windbg用sos的gcroot查引用根(这里由于还有终结者队列的根,实际会让人很迷惑)。可以发现在GC句柄表里有定时器导致资源无法释放。
在.Net下主要有4类地方会持有引用根,从而使得对象在标记阶段被标记,导致GC不会回收该对象。
参考《.Net内存管理宝典》 第八章,垃圾回收-标记阶段
- 线程栈
- GC内部根(跨代引用,类静态变量等)
- 终结器队列
- GC句柄表
这里定时器的引用根在GC句柄表,通过sos可以查到定时器的周期为300ms。由于我们的代码里没有这样的定时器,最终怀疑到DevExpress的代码中,通过检查SOS的引用链 最终发现我们使用的DataLayoutControl有问题。
DevExpress的相关源代码如下:
LayoutControl.cs
private void Initialize() {
SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true);
implementorCore.InitializeComponents();
}
ILayoutControlImplementer.cs
public virtual void InitializeComponents() {
if(AllowCreateRootElement) InitializeRootGroupCore();
InitializeCollections();
InitializeTimerHandler();
InitializeScrollerCore(as_I);
InitializeFakeFocusContainerCore(as_I);
}
public virtual void InitializeTimerHandler()
{
if(AllowTimer) {
this.internalTimerCore = new Timer();
InternalTimer.Interval = 300;
// DevExpress的LayoutControl内部使用这个定时器计算布局等
InternalTimer.Tick += OnTimedEvent;
InternalTimer.Enabled = true;
}
}
protected virtual bool AllowTimer {
get { return true; }
}
internal void OnTimedEvent(object sender, EventArgs e) {
if(as_I.IsUpdateLocked) return;
as_I.ActiveHandler.OnTimer();
}
public virtual void OnTimer() {
AutoScrollByMoving();
InvalidateHotTrackItemIfNeed();
}
- DataLayoutControl继承自LayoutControl,自然就有了该问题。
教训
不用的控件需要主动Dispose,不能Remove就不管了。
Winform的Dispose会自动处理子控件,所以不论我们的用户控件内部如何嵌套。直接对最外层处理Dispose就可以了。
Winform的相关代码如下:
protected override void Dispose(bool disposing)
{
// 对内部维护的资源进行释放
ControlCollection controlCollection = (ControlCollection)Properties.GetObject(PropControlsCollection);
if (controlCollection != null)
{
for (int i = 0; i < controlCollection.Count; i++)
{
Control control = controlCollection[i];
control.parent = null;
control.Dispose();
}
Properties.SetObject(PropControlsCollection, null);
}
解决方案代码
public void LoadPluginUI(string pluginID)
{
this.Control[0].Dispose();
Control ctl = GetPluginUI(pluginID);// ctl是我们插件的用户控件
this.Control.Add(ctl);
}
DevExpress 的LayoutControl控件导致资源无法释放的问题处理的更多相关文章
- DevExpress Winform 常用控件
Ø 前言 DevExpress 控件的功能比较强大,是全球知名控件开发公司,对于开发 B/S 或 C/S 都非常出色,可以实现很炫且功能强大的效果. DevExpress Winform 常用控件是 ...
- DevExpress Winform 通用控件打印方法(允许可自定义边距) z
DevExpress Winform 通用控件打印方法,包括gridcontrol,treelist,pivotGridControl,ChartControl,LayoutControl...(所有 ...
- DevExpress之GridControl控件小知识
DevExpress之GridControl控件小知识 一.当代码中的DataTable中有建数据关系时,DevExpress 的 GridControl 会自动增加一个子视图 .列名也就是子表的字段 ...
- WPF Popup 控件导致被遮挡内容不刷新的原因
WPF Popup 控件导致被遮挡内容不刷新的原因 周银辉 今天在写一个WPF控件时用到了Popup控件,很郁闷的情况是:当popup关闭时,原来被popup挡住的界面部分不刷新,非要手动刷新一下(比 ...
- (转)WPF控件开源资源
(转)WPF控件开源资源 Textbox Drag/Drop in WPFhttp://www.codeproject.com/Articles/42696/Textbox-Drag-Drop-in- ...
- DevExpress的GridControl控件更新數據問題解決辦法
開發WPF程序時,使用Devexpress的GridControl控件用ItemSource綁定數據,在頁面進行編輯時,當屬性繼承INotifyPropertyChanged接口時會同步更新後臺數據. ...
- DevExpress的Web控件汉化方法
原文:DevExpress的Web控件汉化方法 项目中用到devexpress的web控件,机器没有安装devexpress控件,直接在项目中引用的dev的dll,项目运行时发现都是英文界面,所以解决 ...
- 使用DevExpress.XtraTabbedMdi.XtraTabbedMdiManager控件来加载MDI窗体
使用DevExpress.XtraTabbedMdi.XtraTabbedMdiManager控件来加载MDI窗体 [csharp] view plaincopyprint? <SPAN ...
- 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载)
前言 上一篇博文<玩转控件:重绘ComboBox —— 让ComboBox多列显示>中,根据大家的回馈,ComboBox已经支持筛选了,更新见博文最后最后最后面. 奇葩 这两天遇到 ...
- WPF控件开源资源
(转)WPF控件开源资源 Textbox Drag/Drop in WPFhttp://www.codeproject.com/Articles/42696/Textbox-Drag-Drop-in- ...
随机推荐
- 2021 CCPC 威海站 VP记录(题解)
2021 CCPC 威海站 VP记录(题解) 题目顺序为vp时开题顺序: A - Goodbye, Ziyin! 签到,连边数小于等于2的可以作为二叉树根,若有大于4的直接输出0. code: voi ...
- 一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 31.线程池复用的原理 32.spring是什么? 33.对Aop的理解 34.对IOC的理解 35.BeanFactor ...
- 2、yaml配置文件当中的坑(数字的定义和支持进制书写格式)
6.进制数的转换 6.1.问题回顾 我记得我刚刚开始使用SpringBoot的时候,有一天在做到SpringBoot整合第三方技术的时候 我刚好在那天学习到整合Mybatis,做Web项目嘛,不连数据 ...
- python face_recognition安装及各种应用
1.安装 首先,必须提前安装cmake.numpy.dlib,其中,由于博主所用的python版本是3.6.4(为了防止不兼容,所以用之前的版本),只能安装19.7.0及之前版本的dlib,所以直接p ...
- ElasticSearch之Quick.ElasticSearch.Furion组件的使用
ElasticSearch 使用说明 本章,我们主要讲解在.Net 中对Quick.ElasticSearch.Furion的使用进行介绍! ElasticSearch 的官方客户端 API 文档地址 ...
- Spring三级缓存解决循环依赖
前提知识 1.解决循环依赖的核心依据:实例化和初始化步骤是分开执行的 2.实现方式:三级缓存 3.lambda表达式的延迟执行特性 spring源码执行逻辑 核心方法refresh(), popula ...
- 第2-3-4章 上传附件的接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss
目录 5.3 接口开发-上传附件 5.3.1 接口文档 5.3.2 代码实现 5.3.3 接口测试 5.3 接口开发-上传附件 第2-1-2章 传统方式安装FastDFS-附FastDFS常用命令 第 ...
- 【OpenStack云平台】网络控制节点 HA 集群配置
个人名片: 因为云计算成为了监控工程师 个人博客:念舒_C.ying CSDN主页️:念舒_C.ying 网络控制节点运行在管理网络和数据网络中,如果虚拟机实例要连接到互联网,网络控制节点也需要具备 ...
- 我引用中没有Spire.Pdf,但是发现无法解析的“Spire.Pdf”的不同版本之间存在冲突
问题: 导出错误!未能加载文件或程序集"Spire.Pdf, Version=8.6.1.0, Culture=neutral, PublicKeyToken=663f351905198cb ...
- python基础语法/简单数据类型/常量与变量
今日内容概要 PEP-8规范/python基础语法 变量与常量定义 基本数据类型(整形int,字符串str,浮点型float,字典dict,列表list) 到此我们前期的配置已经可以满足我们正常编写代 ...