什么定义了内存流的容量
What defines the capacity of a memory stream
我正在使用以下代码计算对象(正在填充的列表)的大小:
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;
A初始点memoryStreamObject
的容量是1024
后来(在列表中添加更多元素后)显示为 2048。
而且它似乎随着流内容的增加而增加。那么capacity在这个场景中的作用是什么?
内存流和列表的容量的目的是底层数据结构实际上是一个数组,并且数组不能动态调整大小。
所以一开始你使用一个小的数组,但是一旦你添加了足够的数据使得数组不再足够大你需要创建一个新数组,复制所有数据旧数组到新数组,然后从现在开始切换到使用新数组。
这个create+copy需要时间,数组越大,时间越长。因此,如果您每次都将数组 调整 足够大,那么每次写入内存流或向列表添加新元素时,您都会有效地执行此操作。
相反,你有一个能力,说 "you can use up to this value before having to resize" 来减少你必须执行的创建+复制循环的次数。
例如,如果您要一次向这个数组写入一个字节,并且没有这个容量概念,那么每多出一个字节就意味着一个完整的创建+复制整个数组的周期。相反,使用问题中的最后一个屏幕截图,您可以一次写入一个字节,在必须执行此创建+复制循环之前再写入 520 次。
所以这是一个性能优化。
一个额外的好处是,重复分配稍大的内存块最终会产生内存碎片,因此您可能会遇到 "out of memory" 异常,减少此类分配的数量也有助于避免这种情况。
计算此容量的典型方法是每次将其加倍。
这是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))
我正在使用以下代码计算对象(正在填充的列表)的大小:
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;
A初始点memoryStreamObject
的容量是1024
后来(在列表中添加更多元素后)显示为 2048。
而且它似乎随着流内容的增加而增加。那么capacity在这个场景中的作用是什么?
内存流和列表的容量的目的是底层数据结构实际上是一个数组,并且数组不能动态调整大小。
所以一开始你使用一个小的数组,但是一旦你添加了足够的数据使得数组不再足够大你需要创建一个新数组,复制所有数据旧数组到新数组,然后从现在开始切换到使用新数组。
这个create+copy需要时间,数组越大,时间越长。因此,如果您每次都将数组 调整 足够大,那么每次写入内存流或向列表添加新元素时,您都会有效地执行此操作。
相反,你有一个能力,说 "you can use up to this value before having to resize" 来减少你必须执行的创建+复制循环的次数。
例如,如果您要一次向这个数组写入一个字节,并且没有这个容量概念,那么每多出一个字节就意味着一个完整的创建+复制整个数组的周期。相反,使用问题中的最后一个屏幕截图,您可以一次写入一个字节,在必须执行此创建+复制循环之前再写入 520 次。
所以这是一个性能优化。
一个额外的好处是,重复分配稍大的内存块最终会产生内存碎片,因此您可能会遇到 "out of memory" 异常,减少此类分配的数量也有助于避免这种情况。
计算此容量的典型方法是每次将其加倍。
这是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))