我正在计算对象的大小(正在填充的List),使用以下代码:
long myObjectSize = 0;
System.IO.MemoryStream memoryStreamObject = new System.IO.MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryBuffer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryBuffer.Serialize(memoryStreamObject, myListObject);
myObjectSize = memoryStreamObject.Position;
随着流内容的增加,它似乎在增加。那么这种情况下容量的目的是什么。?
答案 0 :(得分:4)
内存流和列表容量的目的是底层数据结构实际上是一个数组,并且无法动态调整数组的大小。
首先,你要使用一个小(ish)大小的数组,但是一旦你添加了足够的数据以便数组不再足够大你需要创建一个新数组,复制旧数据中的所有数据数组到新数组,然后从现在开始切换到使用新数组。
这个create + copy需要时间,数组越大,执行此操作所需的时间就越长。因此,如果您每次都调整 这个数组的大小,那么每次写入内存流或向列表中添加新元素时,都会有效地执行此操作。
相反,你有一个容量,说“你必须在调整大小之前使用这个值”,以减少你必须执行的创建+复制周期的数量。
例如,如果您要一次向该数组写入一个字节,并且没有此容量概念,则每个额外字节将意味着整个数组的create + copy的一个完整周期。相反,使用问题中的最后一个屏幕截图,您可以一次写入一个字节,在执行此创建+复制周期之前再多写520次。
所以这是性能优化。
另外一个好处是,重复分配稍大一些的内存块最终会破坏内存,因此您可能会遇到“内存不足”的异常,减少此类分配的数量也有助于避免这种情况。
计算此容量的典型方法是每次加倍。
答案 1 :(得分:4)
这是由MemoryStream的内部实现引起的。 Capacity属性是内部缓冲区的大小。如果使用固定大小的缓冲区创建MemoryStream,这是有意义的。但是在你的情况下,如果缓冲区太小,MemoryStream会增长,实际的实现会使缓冲区的大小加倍。
MemoryStream代码
private bool EnsureCapacity(int value)
{
if (value < 0)
{
throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
}
if (value > this._capacity)
{
int num = value;
if (num < 256)
{
num = 256;
}
if (num < this._capacity * 2)
{
num = this._capacity * 2;
}
if (this._capacity * 2 > 2147483591)
{
num = ((value > 2147483591) ? value : 2147483591);
}
this.Capacity = num;
return true;
}
return false;
}
写在
中的某个地方int num = this._position + count;
// snip
if (num > this._capacity && this.EnsureCapacity(num))