简单介绍一下MemoryStream
MemoryStream是内存流,为系统内存供给读写操纵,,由于MemoryStream是通过无标记字节数组构成的,可以说MemoryStream的性能可以
算对照超卓,所以它继承起了一些其他流进行数据交换时的中间事情,同时可降低应用措施中对姑且缓冲区和姑且文件的需要,其实MemoryStream
的重要性不亚于FileStream,在很多场合我们必需使用它来提高性能
MemoryStream和FileStream的区别
前文中也提到了,FileStream主要对文件的一系列操纵,属于对照高层的操纵,但是MemoryStream却很不一样,它更趋向于底层内存的操纵,这样
能够到达更快的速度和性能,也是他们的根柢区别,很多时候,操纵文件都需要MemoryStream来实际进行读写,最后放入到相应的FileStream中,
不只如此,在诸如XmlWriter的操纵中也需要使用到MemoryStream提高读写速度
通过部分源码深入了解下MemoryStream
由于篇幅关系,本篇无法详细说明其源码,还请大家海涵,这里我就简单介绍下Write()要领的源码
public override void Write(byte[] buffer, int offset, int count) { if (!_isOpen) __Error.StreamIsClosed(); if (!_writable) __Error.WriteNotSupported(); if (buffer==null) throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer")); if (offset < 0) throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (buffer.Length - offset < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); int i = _position + count; // Check for overflow if (i < 0) throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong")); if (i > _length) { bool mustZero = _position > _length; if (i > _capacity) { bool allocatedNewArray = EnsureCapacity(i); if (allocatedNewArray) mustZero = false; } if (mustZero) Array.Clear(_buffer, _length, i - _length); _length = i; } if (count <= 8) { int byteCount = count; while (--byteCount >= 0) _buffer[_position + byteCount] = buffer[offset + byteCount]; } else Buffer.InternalBlockCopy(buffer, offset, _buffer, _position, count); _position = i; return; }
关于MemoryStream的源码大家可以本身学习,这里主要分析下MemoryStream最关键的Write()要领,自上而下,最开始的一系列判断大家很容易看大白,
以后对有可能产生的异常应该洞若观火了吧,判断后会取得这段数据的长度 int i=_position+count ,接下来会去判断该数据的长度是否赶过了该流的长度,
如果赶过再去查抄是否在流的可支配容量(字节)之内,(注意下EnsureCapacity要领,该要领会自动扩容stream的容量,但是前提条件是你使用了memoryStream
的第二个结构函数,也就是带有参数是Capaciy)如果赶过了流的可支配容量则将尾巴删除(将赶过部分的数据断根),接下来大家必定会问,为什么要判断count<=8,
其实8这个数字在流中很关键,小我私家认为微软为了性能需要而这样写:当字节小于8时则一个个读,当字节大于八时则用block拷贝的方法,在这个范畴内递减循环
将数据写入流中的缓冲_buffer中,这个缓冲_buffe是memoryStream的一个私有byte数组类型,畅通过读取外部byte数据放入内部阿谁缓冲buffer中,如果流
的长度赶过了8,则用Buffer.InternalBloackCopy要领进行数组复制,差别于Array.Copy 前者是给与内存位移而非索引位移所以性能上有很大的提升。其实
这个要领的原形是属于c++中的。
分析MemorySteam最常见的OutOfMemory异常
先看下下面一段很简单的测试代码
//测试byte数组 假设该数组容量是256M byte[] testBytes=new byte[256*1024*1024]; MemoryStream ms = new MemoryStream(); using (ms) { for (int i = 0; i < 1000; i++) { try { ms.Write(testBytes, 0, testBytes.Length); } catch { Console.WriteLine("该内存流已经使用了{0}M容量的内存,该内存流最大容量为{1}M,溢出时容量为{2}M", GC.GetTotalMemory(false) / (1024 * 1024),//MemoryStream已经消耗内存量 ms.Capacity / (1024 * 1024), //MemoryStream最大的可用容量 ms.Length / (1024 * 1024));//MemoryStream当前流的长度(容量) break; } } } Console.ReadLine();
由于我们设定了一个256M的byte(有点恐怖),看下溢出时的状态
从输出功效看,MemoryStream默承认用最大容量是512M 产生异常时正好是其最大容量,聪明的你必定会问:如果同时使用2个MemoryStream甚至于多个内存
是怎么分配的?很好,还是用代码来看下输出功效,可以明显看出内存平均分给了2个MemoryStream但是最大容量还是512M
但是问题来了,假设我们需要操纵对照大的文件,该怎么办呢?其实有2种要领能够搞定,一种是前文所说的分段措置惩罚惩罚,我们将byte数组分成等份进行
措置惩罚惩罚,还有一个要领等于尽量增加MemoryStream的最大可用容量(字节),我们可以在声明MemoryStream结构函数时操作它的重载版本:
MemoryStream(int capacity)