【问题标题】:Real buffers usage guid-lines真正的缓冲区使用指南
【发布时间】:2014-01-08 18:41:19
【问题描述】:

现在我开始研究大量使用缓冲区的典型应用程序。我很惊讶我找不到关于这个主题的清晰指南。

我有几个问题。

1) 我什么时候更喜欢在非托管堆内存中使用缓冲区而不是托管内存? 我知道.net 上的对象分配比非托管堆上的更快,并且由于 GC 开销,.net 上的对象销毁要昂贵得多,所以我认为使用非托管会快一点。我什么时候应该使用 fixed{} 以及 Marshal.AllocHGlobal() 什么时候?

2) 据我了解,如果缓冲区可能在一段时间后(基于用户操作)被重用,那么对 .net 中的托管和非托管缓冲区使用周参考会更有效,不是吗?

【问题讨论】:

    标签: c# .net buffer


    【解决方案1】:

    尝试使用本机“缓冲区”手动管理内存分配对于 .NET 来说是最困难的。您不能将托管类型分配到非托管缓冲区中,因此它们只能用于结构化数据,在这种情况下,与简单的托管数组相比几乎没有优势(它将连续保留在内存中,等等)。

    一般来说,尝试管理您分配和释放对象的方式,并尝试在适当的时候手动重用它们(当且仅当内存压力对您来说是个问题)时,通常是一种更好的方法。

    至于你的一些具体观点:

    我知道 .net 上的对象分配比非托管堆上的更快,并且由于 GC 开销,.net 上的对象销毁要昂贵得多,所以我认为使用非托管会快一点。

    我认为您在这里的假设有些缺陷。在分配点,对象分配在 .NET 中通常更快,因为 CLR 可能已经预先分配了它可以使用的内存。对象“销毁”在 .NET 上也更快,尽管由于 GC 会产生延迟成本,可能会更高一些(尽管并非总是如此)。这里有很多因素,主要集中在对象生命周期 - 如果您允许将对象提升到 Gen1 或特别是 Gen2,那么事情可能会变得难以跟踪和衡量,因为 GC 压缩成本可能会更高。

    什么时候应该使用 fixed{},什么时候应该使用 Marshal.AllocHGlobal()?

    一般来说,你会(非常)很少在 C# 中使用它们。通常最好不要固定内存,并允许 GC 正常工作,这反过来又会导致总体上更好的 GC 启发式。

    2) 据我了解,如果缓冲区可能在一段时间后(基于用户操作和用户操作)可以重复使用,那么对 .net 中的托管和非托管缓冲区使用周参考会更有效,不是吗?

    不一定。重用对象并使它们保持比必要的更长的时间也有一些严重的缺点。这可能会保证内存将被提升到 Gen2,这可能会使生活变得更糟,而不是更好。

    通常情况下,我的建议是相信系统,但要随心所欲地衡量。当且仅当您发现真正的问题时,几乎总有办法解决这些特定问题(无需求助于非托管或手动管理内存缓冲区)。在处理托管代码库时,使用原始内存绝对是最后的手段。

    【讨论】:

    • 当我需要将缓冲区传递给本机 API 时,传递托管固定对象或堆上的非托管缓冲区会更好吗? (例如我需要用零填充文件的缓冲区)
    • @BransDs 对于您的示例,我只使用托管 API 来填充文件。不过,一般来说,固定和传递固定指针将避免不必要的复制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    相关资源
    最近更新 更多