随笔分类 -  .NET陷阱

摘要:好长时间没有写博文了,今天继续。这次跟大家分享的内容起因于对一个枚举值列表的序列化,下面简化后的代码即能重现。为了明确起见,我显式指定了枚举的基础类型。// 定义一个枚举类型。public enum SomeEnum :int{ First, Second, Third, .... 阅读全文
posted @ 2014-08-06 18:46 Bruce Bi 阅读(1557) 评论(9) 推荐(1) 编辑
摘要:我们在开发过程中曾经遇到过一个奇怪的问题:当软件加载了很多比较大规模的数据后,会偶尔出现OutOfMemoryException异常,但通过内存检查工具却发现还有很多可用内存。于是我们怀疑是可用内存总量充足,但却没有足够的连续内存了——也就是说存在很多未分配的内存空隙。但不是说.NET运行时的垃圾收集器会压缩使用中的内存,从而使已经释放的内存空隙连成一片吗?于是我深入研究了一下垃圾回收相关的内容,最终明确的了问题所在——大对象堆(LOH)的使用。如果你也遇到过类似的问题或者对相关的细节有兴趣的话,就继续读读吧。如果没有特殊说明,后面的叙述都是针对32位系统。首先我们来探讨另外一个问题:不考虑非 阅读全文
posted @ 2013-04-16 20:42 Bruce Bi 阅读(10134) 评论(43) 推荐(32) 编辑
摘要:大家可能都遇到过没有取消事件监听而带来的一些问题,像内存泄露、访问无效数据等。当我们写下如下代码时:source.StateChanged += observer.SourceStateChangedHandler实际上source会保持有对observer的一个引用,所以如果source的生命期长于observer的话,则当其它地方不引用observer时,如果不显示解除监听,则observer不会被垃圾回收。这可能会带来两个问题:其一,如果observer占用了大量内存的话,则这部分内存不会被释放;其二,程序的其它地方可能已经处于不一致的状态,这样当source.StateChanged事 阅读全文
posted @ 2013-04-08 18:43 Bruce Bi 阅读(2462) 评论(5) 推荐(1) 编辑
摘要:在我们的代码中,有时会在控件中添加对数据对象的引用。比如使用树节点的Tag属性保存相应的对象,以便在界面操作中能简单的进行访问。因为其它地方不会引用这些数据,所以我们期望在控件被销毁时,垃圾回收机制能回收相应的内存。但当软件运行了一段时间后,内存使用量会变得非常大。下面是简化后的示例代码: 1 using System; 2 using System.Windows.Forms; 3 4 namespace MemoryLeak 5 { 6 public class MainForm : Form 7 { 8 private Button holderButt... 阅读全文
posted @ 2013-04-03 11:21 Bruce Bi 阅读(915) 评论(3) 推荐(1) 编辑
摘要:我们的软件中需要很多自定义的光标,以便在用户交互过程中进行必要的提示。我们开始的做法是将光标放到资源文件中,然后用类似下面的代码加载:var cursor = new Cursor(new MemoryStream(Resource.OpenHandIcon));... ...if (useDefaultCursor){ control.Cursor = Cursors.Default;}else{ control.Cursor = cursor;}但在测试过程中应该显示自定义光标时,总是时而替换成功,时而替换不成功。原来是.NET中提供的Cursor类的问题,Cursor的构造函... 阅读全文
posted @ 2013-04-02 17:11 Bruce Bi 阅读(591) 评论(1) 推荐(0) 编辑
摘要:代码中有一个类,其中包含一个字典(Dictionary<Key, Value>),本来想让前者实现IDeserializationCallback接口,以便在反序列化时根据字典的内容做一些初始化工作,结果循环字典元素的代码就是不走。费了好大劲才找到原因,先来看有问题的代码: 1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Runtime.Serialization; 5 using System.Runtime.Serialization.Formatters 阅读全文
posted @ 2013-04-01 17:40 Bruce Bi 阅读(1173) 评论(1) 推荐(1) 编辑