【问题标题】:Can I use less memory when using DeflateStream?使用 DeflateStream 时可以使用更少的内存吗?
【发布时间】:2010-10-29 03:08:58
【问题描述】:

我的应用程序需要解压缩包含大量 Deflate 压缩块(以及其他类型的压缩和加密)的文件。内存分析表明,deflate 流构造函数负责在其生命周期内分配应用程序的大部分内存(54.19%,其次是 DeflateStream.read,为 12.96%,其他所有内存均低于 2%)。

换个角度来看,每个文件块通常是 4KiB(解压后),而 DeflateStream 的构造函数分配的空间略大于 32KiB(大概是用于滑动窗口)。垃圾收集器有一个现场日,因为所有这些放气流几乎不会持续任何时间(每个都在下一个进入之前消失)!再见缓存效率。

我可以继续使用 DeflateStream,但我想知道是否有更好的选择。也许是一种重置流并再次使用它的方法?

【问题讨论】:

    标签: .net memory deflatestream


    【解决方案1】:

    两个 cmets 没有任何实际测量的好处来支持这一点:

    • 我想您会发现这些临时缓冲区的分配(和归零)所花费的时间与实际解压缩所花费的时间相比可以忽略不计。
    • 这些缓冲区是高度瞬态的,这意味着尽管在应用程序的生命周期中它可能占内存的 50%,但它们都不会同时存在。请注意,这也不应该对缓存效率造成太大影响...我想这些缓冲区中的大多数在缓存内存中的使用时间不会超过它们的使用时间,因为这些页面会很快过时。

    简而言之,除非您对 deflate 流有可衡量的问题(在速度或绝对内存使用方面),否则我会继续使用它...最好使用您知道的解决方案,而不是引入另一个可能有的解决方案一组完全不同的更难处理的问题。

    【讨论】:

    • 我仔细查看了时间分析,发现您是正确的。大部分时间似乎都花在了处理输出的函数上。
    【解决方案2】:

    您是否有任何实际的性能问题,或者您只是担心内存使用情况?

    大多数对象都是短命的,因此内存管理和垃圾收集器旨在有效地处理短命的对象。框架中的许多类被设计为使用一次然后丢弃,以使其寿命更短。

    如果您尝试挂在对象上,它们更有可能在垃圾回收中幸存下来,这意味着它们将从一个堆代移到另一代。堆生成不仅仅是对象的逻辑划分,而是对象实际上从一个内存区域移动到另一个内存区域。垃圾收集器的工作原理通常是将堆中的所有活动对象移至下一代,然后清空堆,因此成本高的是长期存活的对象,而不是短期存活的对象。

    由于这种设计,内存吞吐量较高而实际内存使用量保持较低是很正常的。

    【讨论】:

    • 由于工作负载稍大的性能问题,我正在检查一般区域,但我通过将操作移出 UI 线程来解决此问题。这个内存问题是我在分析问题时注意到的事情之一。感觉就像我正在分配,更重要的是,当我只需要一个时,将所有这些 32KiB 缓冲区归零。
    【解决方案3】:

    DotNetZip 中有一个 DeflateStream,实际上是 .NET BCL 中内置 DeflateStream 的替代品。 Ionic.Zlib.DeflateStream 有一个可调的缓冲区大小。我不知道它是否会在您的场景中带来更好的内存效率,但它可能值得一试。 Here's the doc

    我没有测试解压,而是压缩。在我的测试中,对于我压缩的数据子集,我发现将缓冲区大小扩展到 4k 以上的回报有限。另一方面,即使缓冲区为 1024 字节,您仍然可以获得准确、正确的压缩,尽管它的效果较差。我想你会在解压中看到类似的结果。

    在任何一种情况下,都不能直接从公共界面设置窗口大小。但是,它是开源的,您可以根据需要轻松修改默认的 Wwindow 大小。此外,如果您认为它很有价值,我可以请求将窗口大小公开为 DeflateStream 上的可设置参数。我没有暴露它,因为没有人要求它。还是?

    你说你也有其他压缩。如果您使用 Zlib 或 GZip,DotNetZip 包中也有 ZlibStream 和 GZipStream。

    如果您想做 Zip 文件,您需要完整的 DotNetZip 库(Ionic.Zip.dll,大约 400k)。如果你只是在做 {Deflate, Zlib, GZip}Stream,那么就有一个 Ionic.Zlib.dll,大约 90k。

    DotNetZip 是免费的,但 donations are encouraged

    【讨论】:

    • 听起来很有趣。我不认为暴露窗口大小是必要的或一个好主意。问题是我必须分配很多并且它们很大。如果我要解决这个问题,我会通过允许流在新的子流上重置为其初始状态来解决它。
    • 窗口大小由 C 库 zlib 公开。所以不是史无前例的。但是对于我提供的抽象,我没有将它作为 DeflateStream 的一部分公开。至于回收缓冲区,您绝对可以使用较低级别的 ZlibCodec 类来做到这一点。 Is 是一个 Zlib 编码器/解码器。 DeflateStream 是建立在它之上的。如果你有缓冲区要解压缩,而不是流,ZlibCodec 可能是要走的路。
    • ps:如果你使用 ZlibCodec 类,你也可以设置窗口大小。
    猜你喜欢
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 2021-10-09
    • 2019-04-20
    • 2017-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多