解决 OutOfMemoryException 的最佳方法? (C#)
Best way to resolve OutOfMemoryException? (C#)
我在 Visual Studio 2017 RC 中使用 C#、.Net 4.6.x 和用于 WinForms 的 Telerik 控件。该应用程序由使用 RadRibbon 和 RadPageView 的 "main" window 组成。 RadPageView 根据第一页的搜索表单动态填充页面,或者由用户请求新的空白表单。其他页面继承自 RadPageViewPage,并有一个额外的 属性,称为 "TQC"。 TQC 是指在页面上加载的自定义控件。
TQC 在 RadPageViewPages 中有几个下拉列表和文本区域,它们都包含在 TQC 对象内的 RadPageView 控件中。它不会将任何数据绑定到它的控件,直到它的 RPVP(class 继承 RadPageViewPage)被选中。其中一个下拉列表在填充时包含 200 个左右的条目(帐户列表)。
我遇到的问题 运行 是当外部 RadPageView Remove() 页面时,该页面占用的内存没有释放,大约为几百兆字节。这是有问题的,因为目标机器有 4GB 到 8GB 的内存。我尝试将填充控件的数据对象设置为 null 作为关闭事件的一部分,但没有任何改变。我还尝试对 RadPageViewPage 的所有后代显式调用 Dispose() 方法,如下所示:
private void rpvQtabs_PageRemoved(object sender, RadPageViewEventArgs e)
{
foreach (TQC c in e.Page.Controls)
{
foreach (Control ca in c.Controls)
{
foreach (Control cac in ca.Controls)
{
cac.Dispose();
}
ca.Dispose();
}
c.Dispose();
}
e.Page.Dispose();
}
我仍然遇到疯狂的巨大内存泄漏,如果用户查看了 5 个以上的选项卡(即使他们关闭了页面),很快就会出现 OutOfMemoryException。我尝试附加 Performance Profiler,但它在尝试时崩溃了。 VS 2015 目前不是一个选项。如何确保页面得到正确处理,或减少超大下拉列表的内存占用?这是我们第一次尝试使用 Telerik。
回复评论中的问题:
引发错误的对象通常是相对随机的,取决于加载了哪些帐户。这不是无限递归的东西。这是最初加载控件的方式(使用特殊连接 class):
public static List<Account> List(bool includeDefaults = true)
{
//search
var rs = new List<Account>();
string q = "select distinct r.ID, r.name from db.addressbook r";
DataTable dt = new DataTable();
using (var cmd = new CustomConnectionClass())
{
cmd.Safety.Off();
dt = cmd.ExecuteDirectQuery(q);
}
foreach (DataRow r in dt.Rows)
{
var a = new Account();
a.ID = long.Parse(r[0].ToString());
a.Name = r[1].ToString();
rs.Add(a);
}
rs = rs.OrderBy(t => t.ID).ToList();
var n = new Account();
n.ID = 0;
n.Name = "Generic Account";
var o = new Account();
o.ID = 999999;
o.Name = n.Name;
rs.InsertRange(0, new Account[] { n, o });
return rs;
}
经过进一步调查,我能够弄清楚这涉及到 Telerik 如何加载其主题和控件。使下拉列表的所有数据源 static
减少了一点占用空间,但每个选项卡中控件的主题管理器和主题每次都加载为新的。根据设计,当控件关闭和释放时,它们不一定被释放。 UI 的设计必须重新设计以防止用户 运行 内存不足。如果使用标准 WinForms 合并相同的设计,问题就会消失。
我在 Visual Studio 2017 RC 中使用 C#、.Net 4.6.x 和用于 WinForms 的 Telerik 控件。该应用程序由使用 RadRibbon 和 RadPageView 的 "main" window 组成。 RadPageView 根据第一页的搜索表单动态填充页面,或者由用户请求新的空白表单。其他页面继承自 RadPageViewPage,并有一个额外的 属性,称为 "TQC"。 TQC 是指在页面上加载的自定义控件。
TQC 在 RadPageViewPages 中有几个下拉列表和文本区域,它们都包含在 TQC 对象内的 RadPageView 控件中。它不会将任何数据绑定到它的控件,直到它的 RPVP(class 继承 RadPageViewPage)被选中。其中一个下拉列表在填充时包含 200 个左右的条目(帐户列表)。
我遇到的问题 运行 是当外部 RadPageView Remove() 页面时,该页面占用的内存没有释放,大约为几百兆字节。这是有问题的,因为目标机器有 4GB 到 8GB 的内存。我尝试将填充控件的数据对象设置为 null 作为关闭事件的一部分,但没有任何改变。我还尝试对 RadPageViewPage 的所有后代显式调用 Dispose() 方法,如下所示:
private void rpvQtabs_PageRemoved(object sender, RadPageViewEventArgs e)
{
foreach (TQC c in e.Page.Controls)
{
foreach (Control ca in c.Controls)
{
foreach (Control cac in ca.Controls)
{
cac.Dispose();
}
ca.Dispose();
}
c.Dispose();
}
e.Page.Dispose();
}
我仍然遇到疯狂的巨大内存泄漏,如果用户查看了 5 个以上的选项卡(即使他们关闭了页面),很快就会出现 OutOfMemoryException。我尝试附加 Performance Profiler,但它在尝试时崩溃了。 VS 2015 目前不是一个选项。如何确保页面得到正确处理,或减少超大下拉列表的内存占用?这是我们第一次尝试使用 Telerik。
回复评论中的问题:
引发错误的对象通常是相对随机的,取决于加载了哪些帐户。这不是无限递归的东西。这是最初加载控件的方式(使用特殊连接 class):
public static List<Account> List(bool includeDefaults = true)
{
//search
var rs = new List<Account>();
string q = "select distinct r.ID, r.name from db.addressbook r";
DataTable dt = new DataTable();
using (var cmd = new CustomConnectionClass())
{
cmd.Safety.Off();
dt = cmd.ExecuteDirectQuery(q);
}
foreach (DataRow r in dt.Rows)
{
var a = new Account();
a.ID = long.Parse(r[0].ToString());
a.Name = r[1].ToString();
rs.Add(a);
}
rs = rs.OrderBy(t => t.ID).ToList();
var n = new Account();
n.ID = 0;
n.Name = "Generic Account";
var o = new Account();
o.ID = 999999;
o.Name = n.Name;
rs.InsertRange(0, new Account[] { n, o });
return rs;
}
经过进一步调查,我能够弄清楚这涉及到 Telerik 如何加载其主题和控件。使下拉列表的所有数据源 static
减少了一点占用空间,但每个选项卡中控件的主题管理器和主题每次都加载为新的。根据设计,当控件关闭和释放时,它们不一定被释放。 UI 的设计必须重新设计以防止用户 运行 内存不足。如果使用标准 WinForms 合并相同的设计,问题就会消失。