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- ...
随机推荐
- Python编程之子进程管理(subprocess)详解
引言 在写程序时,我们无法避免需要运行外部程序,相较于功能比较简单的os.system(),更加倾向于使用subprocess模块来执行外部程序. 模块介绍 subprocess.run() 使用su ...
- day48-JDBC和连接池04-2
JDBC和连接池04-2 10.数据库连接池 10.5Apache-DBUtils 10.5.1resultSet问题 先分析一个问题 在之前的程序中,执行sql语句后返回的结果集存在如下问题: 关闭 ...
- 4.ElasticSearch系列之基本概念
1. 文档 ElasticSearch是面向文档的,文档是所有可搜索数据的最小单位 文档会被序列化成JSON格式,保存在ES中 每个文档都有一个unique ID #查看前10条文档,了解文档格式 P ...
- uoj221【NOI2016】循环之美
前面部分比较简单,就是无脑化式子,简单点讲好了. 首先肯定在\((x,y)=1\)时才考虑这个分数,要求纯循环的话,不妨猜猜结论,就是y必须和K互质.所以答案是\(\sum_{i=1}^n \sum_ ...
- [Thread] 多线程顺序执行
Join 主线程join 启动线程t1,随后调用join,main线程需要等t1线程执行完毕后继续执行. public class MainJoin { static class MyThread i ...
- 关于针对XSS漏洞攻击防范的一些思考
众所周知,XSS几乎在最常见.危害最大的WEB漏洞.针对这个危害,我们应该怎么防范呢. 下面简单说一下思路. 作者:轻轻的烟雾(z281099678) 一.XSS漏洞是什么 XSS漏洞网上的资料太多, ...
- Linux进程间通信(一)
进程间通信 概念:进程是一个独立的资源分配单位,不同进程之间有关联,不能在一个进程中直接访问另一个进程的资源. 进程和进程之间的资源是相互独立的,一个进程不能直接访问另外一个进程的资源,但是进程和进程 ...
- python深拷贝、浅拷贝
.copy() 浅拷贝 如上图 定义列表A指向一个元素,列表A里面嵌套两层列表分布指向两个元素,定义列表B,列表B=A,列表C浅拷贝列表A 从图上可以看出,列表A和列表B指向的是同一个列表元素,而 ...
- RegExp正则表达式的匹配
JavaScript RegExp 对象 RegExp 对象 正则表达式是描述字符模式的对象. 正则表达式用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具. 语法 var patt=n ...
- 统一的开发平台.NET 7正式发布
在 2020 年规划的.NET 5功能终于在.NET 7 完成了,为微软和社区一起为多年来将不同的开发产品统一起来的努力加冕,未来只有一个.NET, 回顾.NET 20年,从.NET Framewo ...