【问题标题】:Get serialised size of List without having OutOfMemoryException在没有 OutOfMemoryException 的情况下获取 List 的序列化大小
【发布时间】:2013-08-16 15:44:20
【问题描述】:

好吧,明确一点,我知道所有 LOH 的事情和进入 LOH 的大对象(超过 85k)和大列表(超过 40k 元素)。

所以我的问题是,在使用 XMLSerialiser 序列化时我需要知道 List 的大小(我不关心它在 RAM 中占用的空间或类似的东西,我只是想要序列化时的大小)但是如果我尝试序列化一个包含大元素的大列表,我会得到 OutOfMemoryException(我知道为什么)

我想知道的是:是否可以将列表 逐个元素序列化并在循环中累积它的大小,例如: //这将是伪代码

long byteLength = 0;
using(stream)
{
  foreach(element in MyList)
  {
    MemoryStream.Serialise(element);
    byteLength += MemoryStream.Length;

    MemoryStream.Clear();
  }
}

有什么建议吗?


更新: @xanatos 的解决方案做我想做的事情,因为它不会在 ram 中添加一个将存储在 LOH 中的大字节 []

正如@Hans Passant 所说,我为什么要做这种处理的目的似乎很重要,所以:我想知道以 XML 序列化的列表的字节大小,以便能够将列表拆分为多个文件根据其总字节在磁盘上。

【问题讨论】:

  • 是的,但似乎即使我在流中序列化对象,长度和位置似乎也没有好的值......我累积了 MemoryStream.Length 并正在重置 @ 987654323@ 到 0 与 Seek(0,0) 函数
  • 你必须非常绝望才能编写这样的代码,当然有更好的方法。从几个对象开始,通过乘以列表的计数来获得估计值。很不清楚您真正要解决什么问题,大型序列化数据非常适合磁盘而不是内存。
  • 我认为我的问题很清楚,上下文不清楚,因为没有必要。我的问题:我想序列化一个 List 而不在我的 LOH 中序列化它的所有字节。 @xanatos 提交的解决方案修复了它,因为它不会创建一个大的byte[],而只是得到它的Length

标签: c# serialization stream out-of-memory


【解决方案1】:

如果你只需要长度:

class NulStream : Stream
{
    public override bool CanRead
    {
        get { return false;  }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return true; }
    }

    public override void Flush()
    {
    }

    protected long length;

    public override long Length
    {
        get { return this.length; }
    }

    public override long Position
    {
        get
        {
            return this.length;
        }
        set
        {
            throw new NotSupportedException();
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new NotSupportedException();
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotSupportedException();
    }

    public override void SetLength(long value)
    {
        throw new NotSupportedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        this.length += count;
    }
}

using (var nul = new NulStream())
{
    xml.Serialize(nul, lst);
    long length = nul.Length;
}

它是一个 NUL 流......就像 NUL 文件 :-) 它会吃掉你扔给它的东西,并且只保存累积长度。

请注意,从技术上讲,我可以实现SetLength,而Write 应该检查它的参数...但是为什么呢? :-)

【讨论】:

  • 使用这种方法它不会将序列化字节存储在 LOH 中吗?因为这是原来的问题
  • @Tareck117 不,不会。因为XmlSerializer 一次向流发送一个片段,一些实验为 1024-2048 个字节。如果你想看,在 override void Write(...) 中添加这一行:Console.WriteLine(count);
猜你喜欢
  • 2011-10-18
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-26
  • 1970-01-01
相关资源
最近更新 更多