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- ...
随机推荐
- 2022-08-05-欢迎使用_Typecho
layout: post cid: 1 title: 欢迎使用 Typecho slug: start date: 2022/08/05 14:21:51 updated: 2022/08/05 14 ...
- 驱动开发:Win10内核枚举SSDT表基址
三年前面朝黄土背朝天的我,写了一篇如何在Windows 7系统下枚举内核SSDT表的文章<驱动开发:内核读取SSDT表基址>三年过去了我还是个单身狗,开个玩笑,微软的Windows 10系 ...
- linux下rsync的同步
rsync是linux系统下的数据镜像备份工具.使用快速增量备份工具Remote Sync可以远程同步,支持本地复制,或者与其他SSH.rsync****主机同步 文件下载地址: 链接:https:/ ...
- 齐博x1频道的二次开发入门讲解
要进行频道的二次开发,首先我们要先了解一下频道的目录结构,如下图最基本的几个目录admin 后台文件存放目录index 前台文件存放目录member 会员中心存放目录model 数据表模型目录trai ...
- python创建icon图标
def extension_replace(path,extension): for i in range(1,len(path)): if (path[-i] == '.'): new_path = ...
- 基于FPGA的SATA3.0主机控制器IP
SATA3.0 Host Controller IP SATA3.0 Host IP不仅实现了SATA协议的PHY(物理层).Link(链路层)和TRN(传输层),并且实现了CMD(命令层)和APP( ...
- excel公式与快捷操作
将首行的公式,运用到这一整列 1.选中要输入公式的第一个单元格,SHIFT+CTRL+方向键下,在编辑栏中输入公式,按下CTRL+回车: 2.先输入要填充的公式,按下SHIFT+CTRL+方向键下,再 ...
- (GDB) GDB调试技巧,调试命令
调试时查看依赖DSO pidof tvm_rpc_server cat /proc/<pid_of_tvm_rpc_server>/maps 子进程调试 1.vscode -- launc ...
- 【Devexpres】spreadsheetControl冻结行
Worksheet worksheet = this.spreadsheetControl1.ActiveWorksheet; worksheet.Import(datatable, true, 0, ...
- Devexpress控件searchLookUpEdit获得选中行的其他列数据
使用searchLookUpEdit控件获得选中行的其他列的数据.比如有一列代码列和一列描述.那么我们选中一行后想获得选中的代码和描述.可以在searchLookUpEdit1_EditValueCh ...