c# - .Net运行时 "understand"该结构如何仍然有引用

标签 c# .net garbage-collection

问题是 .Net 运行时如何理解使用 Marshal.StructureToPtr 放置到内存中的结构字段,不得由 GC 释放。

在场景下方。

我有以下结构:

[StructLayout(LayoutKind.Sequential)]
public struct SomeStruct
{
    public string s;
    public Stream stream;

    public SomeStruct(string s)
    {
        this.s = s;
        this.stream = new MemoryStream(0x100);
    }
}

有一个方法可以实例化该结构并将其放入内存:

static IntPtr GetStructRawData()
{
    IntPtr ptr = Marshal.AllocHGlobal(1024);
    Marshal.StructureToPtr(new SomeStruct("hi"), ptr, false);
    return ptr;
}

然后我可以从原始内存中创建新的结构:

IntPtr ptr = GetStructRawData();

GC.Collect();

SomeStruct struct2 = (SomeStruct)Marshal.PtrToStructure(ptr, typeof(SomeStruct));

struct2 确实包含正确的字符串(“hi”)和正确的流之后。因此,似乎存在对该字符串和 struct1 流的引用。但是引用文献是什么呢?运行时如何理解字符串和流不能被收集?

最佳答案

But what holds the references? How does the runtime understands that the string and the stream must not be collected?

这里的字符串是一种特殊情况;它实际上是一个实习字符串(通过 ldstr 加载),因此它已经由实习表作为根。

但是MemoryStream...坦率地说,它没有root。您的代码本质上是损坏且危险的,并且随时可能会严重失败。可以随时收集或移动(压缩)对象,这会在非托管内存中留下损坏的引用,因为 GC 不会查看非托管内存

我相信你的代码目前只是“工作”,因为 GC 并没有对你进行攻击。另请记住:GC 不会删除对象;而是会删除对象。如果 GC 只是决定将 MemoryStream 视为已收集,您仍然可以再次与它对话,而不会提示,如果内存暂时看起来还不错。但这只是出于错误的原因。

在非托管内存中引用是一个可怕的想法,会伤害你

如果您要使用非托管内存,where T : unmanaged 约束可能会成为您的救星。它可以防止您陷入这种情况,但作为必要限制了您可以做的事情。含义:您不能拥有这些字段。

关于c# - .Net运行时 "understand"该结构如何仍然有引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60226665/

相关文章:

c# - DAO 的类级错误处理程序

c# - Xamarin Android 支持库 v4(不完整)?

c# - 在编译时捕获对 decimal.ToString 的调用

c# - 事件监听器委托(delegate)中的自引用 (C#)

java - 在 C# 和 java(具有 GC 的语言)中访问硬编码映射或数组等的最佳方法

javascript - 我如何测试我的 web api Post Web 方法以了解内部发生了什么?

c# - 如何添加xml :lang ="en" to <html> tag

c# - 什么是 Windows IPC 方法

c# - 如何使用 1 个计时器入队并使用另一个计时器出队

lua 用户数据 C++ 析构函数