WPF:警惕TextBox会占用过多内存

原文:WPF:警惕TextBox会占用过多内存

问题源自这篇文章:WPF的TextBox产生内存泄露的情况

整个问题是这样的,文章作者演示使用类似下方的代码来不停地像WPF的TextBox控件赋值:

for (int i = 0; i < 10000; i++)

{

    //tbx是界面上的TextBox变量

    tbx.Text += string.Format("{0}\n", i);

}

然后会出现程序占用过多内存的问题。

 

很快在那篇文章的评论中有人指出这个和WPF没有关系,因为频繁得拼接字符串会产生过多重复字符串对象,即使不显示在TextBox控件上,也会会占用过多内存的。

但是原文作者又在回复中讲到他做了相关测试,但是却不会出现占用非常多的内存的情况。

最后问题不了了之。

 

我做了下测试,一种是不断拼接字符串并显示在TextBox中:

//我们就拿个小数字1万来做示例

for (int i = 0; i < 10000; i++)

{

    //tbx是界面上的TextBox变量

    tbx.Text += string.Format("{0}\n", i);

}

 

程序运行后任务管理器显示55.5 MB的内存。(环境:.NET 4.5/Debug编译/64位)

 

接着测试另一种情况:先拼接字符串,最后才显示在TextBox中:

var str = String.Empty;

//我们就拿个小数字1万来做示例

for (int i = 0; i < 10000; i++)

{

    //tbx是界面上的TextBox变量

    str += String.Format("{0}\n", i);

}

tbx.Text = str;

 

运行后显示24.1 MB。

如果把最后一句删掉,也就是根本不在TextBox中显示。运行后是23.4 MB。

 

很明显,整个问题确实是和WPF有关系的,但也不是因为原文作者认为的字符串拼接所造成的。真正的问题是TextBox(更准确地说是其父类:TextBoxBase)的UndoLimit属性。也就是说TextBox会因为频繁修改值而堆积过多的撤销项目项目。就如同Visual Studio的撤销列表一样:

这部分项目会占用过多的内存空间。

 

在.NET 3.5和4.0:TextBoxBase.UndoLimit的值默认是-1。代表如果内存够用的话,撤销列表会无限大。(这个有点恐怖)

在.NET 4.5中:TextBoxBase.UndoLimit的值默认是100。

 

我们可以吧TextBoxBase.UndoLimit设置成0(或者把IsUndoEnabled设置成False),也就是命令TextBox不支持撤销功能。再次运行第一次的代码:

//禁止撤销

tbx.UndoLimit = 0;

for (int i = 0; i < 10000; i++)

{

    //tbx是界面上的TextBox变量

    tbx.Text += string.Format("{0}\n", i);

}

 

运行后,任务管理器显示29.4 MB(几秒后又变成了24 MB)。而没有设置UndoLimit,也就是.NET 4.5中默认值是100的情况下,占用内存则能飙升到55.5 MB。在.NET 3.5或者4下可能会更大,因为默认是没有限制的。

 

那么问题的解决方案是:

适当设置WPF的TextBox.UndoLimit(尤其是.NET 3.5/4.0环境下,默认值-1太可怕了)。当然这仅仅应用在频繁设置TextBox值的情况下,如果没有此类情况,无需担心。另外也要注意如果要进行频繁字符串拼接操作,请使用TextBoxBase.AppendText或者StringBuilder。

时间: 2024-12-21 04:42:50

WPF:警惕TextBox会占用过多内存的相关文章

火狐浏览器占用过多内存的解决方法

火狐在有些情况下会占用较多的内存(RAM),导致浏览器的反应速度较慢,在极端的情况下甚至会导致浏览器崩溃.下面介绍几种方法帮助减少火狐的内存占用,让您更有效地使用火狐浏览器. 检查安装的附加组件 安装的附加组件(包括扩展.主题.插件)造成浏览器占用过多内存的情况比较常见. 您可以用安全模式启动火狐浏览器,观察内存使用情况.在安全模式下扩展和主题是被禁用的,因此如果在安全模式下内存占用情况有了显著的改善,您可以尝试禁用或卸载某些扩展. 另外,插件(特别是旧版本的插件)经常消耗大量内存.您可以禁用其

QL Server数据库占用过多内存的解决方法

QL Server数据库占用过多内存的解决方法 经常有网友会问,SQL Server占用了太多的内存,而且还会不断的增长:或者说已经设置了使用内存,可它没有用到那么多,这是怎么一回事儿呢? 下面,我们来具体看以看SQL Server是怎样使用内存的. 最大的开销一般是用于数据缓存,如果内存足够,它会把用过的数据和觉得你会用到的数据统统扔到内存中,直到内存不足的时候,才把命中率低的数据给清掉.所以一般我们在看statistics io的时候,看到的physics read都是0. 其次就是查询的开

SQL Server数据库占用过多内存的解决方法

经常有网友会问,SQL Server占用了太多的内存,而且还会不断的增长:或者说已经设置了使用内存,可它没有用到那么多,这是怎么一回事儿呢?下面,我们来具体看以看SQL Server是怎样使用内存的. 最大的开销一般是用于数据缓存,如果内存足够,它会把用过的数据和觉得你会用到的数据统统扔到内存中,直到内存不足的时候,才把命中率低的数据给清掉.所以一般我们在看statistics io的时候,看到的physics read都是0. 其次就是查询的开销,一般地说,hash join是会带来比较大的内

解决MSSQL占用过多内存的简单方法

经常看见有人问,MSSQL占用了太多的内存,而且还不断的增长:或者说已经设置了使用内存,可是它没有用到那么多,这是怎么一回事儿呢? 首先,我们来看看MSSQL是怎样使用内存的. 最大的开销一般是用于数据缓存,如果内存足够,它会把用过的数据和觉得你会用到的数据统统扔到内存中,直到内存不足的时候,才把命中率低的数据给清掉.所以一般我们在看statistics io的时候,看到的physics read都是0. 其次就是查询的开销,一般地说,hash join是会带来比较大的内存开销的,而merge

关于MSSQL占用过多内存的问题

问题 经常看见有人问,MSSQL占用了太多的内存,而且还不断的增长:或者说已经设置了使用内存,可是它没有用到那么多,这是怎么一回事儿呢?首先,我们来看看MSSQL是怎样使用内存的.最大的开销一般是用于数据缓存,如果内存足够,它会把用过的数据和觉得你会用到的数据统统扔到内存中,直到内存不足的时候,才把命中率低的数据给清掉.所以一般我们在看statistics io的时候,看到的physics read都是0.其次就是查询的开销,一般地说,hash join是会带来比较大的内存开销的,而merge

java-jboss 设置jvm,内存占用过多情况

问题描述 jboss 设置jvm,内存占用过多情况 JAVA_OPTS="-Xss256k -Xms4000m -Xmx8000m -Xmn2000m -XX:MaxNewSize=512m -XX:MaxPermSize=512M -XX:+UseParallelGC -XX:ParallelGCThreads=16 -XX:-UseGCOverheadLimit -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/corefile/ -

MySQL 句柄数占用过多的解决方法_Mysql

在Windows下安装MySQL ,用了官方的配置向导生成了my.ini,本以为很安稳了,谁知十多个小时过去之后,系统响应非常慢,看资源管理器的性能卡,发现句柄数竟然达到了10万!怪不得无论使用什么程序都卡得很. 网上搜索一下,大概是说 innodb_buffer_pool_size 这个默认的8M太大,但我已经skip-innodb了啊. 后来又看到一个设置innodb_flush_log_at_trx_commit innodb_flush_log_at_trx_commit  (这个很管用

成员函数-关于实例化一个类时占用的内存大小问题

问题描述 关于实例化一个类时占用的内存大小问题 在PHP语言中,写一个类,如果类的成员函数 很多,会不会增大实例化这个类时占用的内存?如下:class abc{public function __construct(){xxxxxx;xxxxxx;}public function a(){xxxxxx;}public function b(){xxxxxxx;}}//classs那当我实例化它时,是不是函数 越多占的内存越大? 解决方案 函数当然占用一些空间,但是要分清楚函数和调用函数两个概念.

如何解决卡巴斯基杀毒软件占用过多系统资源

用户经常反映在使用卡巴斯基进行病毒查杀时占用过多的系统资源,希望笔者能帮助解决.经过笔者研究,下面就告诉大家如何用最简便的方法来解决. 扫描操作是杀毒软件保护系统的家常便饭了,为了加快扫描速度,可以"告诉"卡巴斯基不必重复扫描已经性查过的旧文件. 打开设置窗口,先单击"扫描"标签页,单击右栏的"自定"按钮.在弹出的窗口选择"扫描程序和文档(按内容)",并勾选"只扫描新的和已更改的文件",然后在"复