什么定义了内存流的容量

suj*_*lil 5 c# memory memorystream capacity

我正在使用以下代码计算对象(正在填充的列表)的大小:

 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;
Run Code Online (Sandbox Code Playgroud)

最初的容量memoryStreamObject1024 在此处输入图片说明

后来(在列表中添加了更多元素之后)显示为2048。 在此处输入图片说明

并且它似乎随着流内容的增加而增加。那么在这种情况下容量的目的是什么?

ang*_*son 6

内存流和列表容量的目的是底层数据结构实际上是一个数组,数组不能动态调整大小。

所以首先你使用一个小(ish)大小的数组,但是一旦你添加了足够的数据使得数组不再足够大,你需要创建一个新数组,将旧数组中的所有数据复制到新阵列,然后从现在开始切换到使用新阵列。

这种创建+复制需要时间,数组越大,执行此操作所需的时间就越长。因此,如果您调整的数组只是每次都足够大,你会有效地做到这一点,你写入内存流,每次或添加新元素到列表中。

相反,您有一个容量,说“在必须调整大小之前,您最多可以使用此值”以减少您必须执行的创建+复制周期数。

例如,如果您一次向这个数组写入一个字节,并且没有这个容量概念,那么每增加一个字节就意味着整个数组的创建+复制的一个完整周期。相反,使用问题中的最后一个屏幕截图,您可以一次写入一个字节,在必须执行此创建+复制循环之前再写入 520 次。

所以这是一个性能优化。

一个额外的好处是,反复分配稍大的内存块最终会导致内存碎片化,因此您可能会面临“内存不足”异常的风险,减少此类分配的数量也有助于避免这种情况。

计算此容量的典型方法是每次将其加倍。


Man*_*utz 5

这是由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;
}
Run Code Online (Sandbox Code Playgroud)

在写某处

int num = this._position + count;
// snip
if (num > this._capacity && this.EnsureCapacity(num))
Run Code Online (Sandbox Code Playgroud)