一、简单介绍一下MemoryStream
MemoryStream是内存流,为系统内存提供读写操作,由于MemoryStream是通过无符号字节数组组成的,可以说MemoryStream的性能可以算比较出色,所以它担当起了一些其他流进行数据交互安时的中间工作,同时可降低应用程序中对临时缓冲区和临时文件的需求,其实MemoryStream的重要性不亚于FileStream,在很多场合,我们必须使用它来提高性能
二、MemoryStream和FileStream的区别
前文中也提到了,FileStream主要对文件的一系列操作,属于比较高层的操作,但是MemoryStream却很不一样,他更趋向于底层内存的操作,这样能够达到更快速度和性能,也是他们的根本区别,很多时候,操作文件都需要MemoryStream来实际进行读写,最后放入相应的FileStream中,不仅如此,在诸如XmlWriter的操作中也需要使用MemoryStream提高读写速度
三、分析MemoryStream最常见的OutOfMemory异常
先看一下下面一段简单的代码
1 //测试byte数组 假设该数组容量是256M 2 var testBytes = new byte[256 * 1024 * 1024]; 3 var ms = new MemoryStream(); 4 using (ms) 5 { 6 for (int i = 0; i < 1000; i++) 7 { 8 try 9 { 10 ms.Write(testBytes, 0, testBytes.Length); 11 } 12 catch 13 { 14 Console.WriteLine("该内存流已经使用了{0}M容量的内存,该内存流最大容量为{1}M,溢出时容量为{2}M", 15 GC.GetTotalMemory(false) / (1024 * 1024),//MemoryStream已经消耗内存量 16 ms.Capacity / (1024 * 1024), //MemoryStream最大的可用容量 17 ms.Length / (1024 * 1024));//MemoryStream当前流的长度(容量) 18 break; 19 } 20 } 21 } 22 Console.ReadLine();
输出结果:
从输出结果来看,MemoryStream默认可用最大容量是1024M,发生异常时正好是其最大容量。
问题来了,假设我们需要操作比较大的文件,该怎么办呢?其实有2种方法可以搞定,一种是分段处理,我们将Byte数组分成等份进行处理,还有一种方式便是增加MomoryStream的最大可用容量(字节),我们可以在声明MomoryStream的构造函数时利用它的重载版本:MemoryStream(int capacity)
到底使用哪种方法比较好呢?其实笔者认为具体项目具体分析,前者分段处理的确能够解决大数据量操作的问题,但是牺牲了性能和时间(多线程暂时不考虑),后者可以得到性能上的优势,但是其允许最大容量是 int.Max,所以无法给出一个明确的答案,大家在做项目时,按照需求自己定制即可,最关键的还是要取到性能和开销的最佳点位,还有一种更恶心的溢出方式,往往会让大家抓狂,就是不定时溢出,就是MemoryStream处理的文件可能只有40M或更小时,也会发生OutOfMemory的异常,关于这个问题,终于在老外的一篇文章中得到了解释,运气还不错,可以看看这篇博文:一种MemoryStream的替代方案,由于涉及到windows的内存机制,包括内存也,进程的虚拟地址空间等,比较复杂,所以大家看他的文章前ÿ