为了将对象的实例传递给“GC.AddMemoryPressure”方法,使用了 C# 语言的哪些机制?

What mechanisms of the C# language are used in order to pass an instance of an object to the `GC.AddMemoryPressure` method?

为了将对象实例传递给 GC.AddMemoryPressure 方法,使用了哪些 C# 语言机制?

我在 CLR via C# 一书中遇到了以下代码示例:

private sealed class BigNativeResource {
    private readonly Int32 m_size;
    public BigNativeResource(Int32 size) {
        m_size = size;
        // Make the GC think the object is physically bigger
        if (m_size > 0) GC.AddMemoryPressure(m_size);
        Console.WriteLine("BigNativeResource create.");
    }
    ~BigNativeResource() {
        // Make the GC think the object released more memory
        if (m_size > 0) GC.RemoveMemoryPressure(m_size);
        Console.WriteLine("BigNativeResource destroy.");
    }
 }

我不明白我们如何将对象的实例与其添加的压力相关联。我没有看到对象引用被传递给 GC.AddMemoryPressure。我们是否将增加的内存压力 (amp) 与对象相关联?

此外,我看不出有任何理由调用 GC.RemoveMemoryPressure(m_size);。按字面意思应该是没有用的。让我自己解释一下。有两种可能:对象实例之间有关联或者没有关联。

在前一种情况下,GC 现在应该 m_size 以便确定优先级并决定何时进行收集。因此,它肯定应该自行消除内存压力(否则 GC 对 remove an object while taking into an account the amp 意味着什么?)。

在后一种情况下,根本不清楚添加和删除放大器的用途。 GC 只能使用定义为 类 实例的根。 IE。 GC只能收集对象。因此,如果对象和放大器之间没有关联,我看不出放大器如何影响 GC(所以我假设存在关联)。

这些方法的存在是为了让 GC 了解托管堆之外的内存使用情况。没有对象传递给这些方法,因为内存与任何特定的托管对象没有直接关系。代码作者有责任正确通知 GC 有关内存使用情况的更改。

GC.AddMemoryPressure(Int64)

… the runtime takes into account only the managed memory, and thus underestimates the urgency of scheduling garbage collection.

极端的例子是你有 32 位应用程序,GC 认为它可以轻松分配近 2GB 的托管 (C#) 对象。作为代码的一部分,您使用本机互操作来分配 1GB。如果没有 AddMemoryPressure 调用,GC 仍然会认为它可以免费等到你 allocate/deallocate 很多托管对象......但是在你分配 1GB 托管对象的时候,GC 运行到奇怪的状态 - 它应该有整个额外的 GB 可以玩,但没有剩下任何东西,所以它必须争先恐后地收集内存。如果 AddMemoryPressure 被正确使用,GC 将有机会调整并更积极地在后台或允许 shorter/smaller 影响的点更早地收集。

AddMemoryPressure 用于声明(此处强调)您在某处分配了合理大小的非托管数据。这个方法是runtime给你的礼遇

该方法的目的是在您自己的责任下声明您在某处拥有逻辑上绑定到某个托管对象实例的非托管数据。垃圾收集器有一个简单的计数器,只需将您指定的数量添加到计数器即可跟踪您的请求。

documentation很清楚:当非托管内存消失时,你必须告诉垃圾收集器它已经消失了。

您需要使用此方法通知垃圾收集器存在非托管内存,但如果关联的对象被释放,则可以释放该内存。然后,垃圾收集器能够更好地安排其收集任务。

I can not understand how do we associate an instance of an object with the pressure it adds.

对象的实例通过调用 AddMemoryPressure 将它添加的压力与对自身的引用相关联。该对象已经具有自身的身份!添加和删​​除压力的代码知道 this 是什么。

I do not see object reference being passed to the GC.AddMemoryPressure.

正确。增加的压力与任何对象之间没有必然关联,并且无论是否存在,GC 都不需要知道该信息即可采取适当的行动。

Do we associate the added memory pressure (amp) with an object at all?

GC 没有。如果您的代码这样做,那是您的代码的责任。

Also, I do not see any reasons in calling the GC.RemoveMemoryPressure(m_size)

这样 GC 就知道额外的压力已经消失了。

I see no way how the amp could affect the GC

加压影响GC!


我认为对这里发生的事情存在根本性的误解。

增加内存压力只是告诉GC,有一些你知道的内存分配事实,GC不知道,但与GC的动作有关。 不要求增加的内存压力与任何对象的任何实例相关联或与任何对象的生命周期相关联

您发布的代码是一种常见模式:一个对象具有与每个实例关联的额外内存,并且它在分配额外内存时增加了相应的压力,并在释放额外内存时将其移除。但是没有要求额外的压力与一个或多个特定对象相关联。如果您在 static void Main() 方法中添加了一堆非托管内存分配,您可能会决定添加与之对应的内存压力,但没有 object 与该额外压力相关联。