代码之家  ›  专栏  ›  技术社区  ›  TalentTuner

CLR对非托管组件的内存管理

c#
  •  9
  • TalentTuner  · 技术社区  · 14 年前

    我有点困惑,可能这个问题很傻吧。

    为非托管组件分配的内存在哪里?

    在我的.net代码中,如果我启动了一个非托管组件,那么该组件将加载到哪里并分配内存?

    CLR marshall如何在托管堆和非托管堆之间调用?

    谢谢你的回复,但我要问的是假设我对User32.Dll做了一个DLLIMPORT,这显然是一个非托管Dll,我在User32.Dll中调用了一些函数,现在我的问题是,CLR如何对这个非托管Dll进行marshall调用?

    4 回复  |  直到 14 年前
        1
  •  10
  •   Hans Passant    14 年前

    一开始很容易。pinvoke封送拆收器首先调用LoadLibrary并传递指定的DLL名称DllImportAttribute.Value属性。在您的例子中,已经加载了user32.dll,因为它是由.NET引导程序加载的,它的引用计数只是增加了。但通常Windows加载程序会将DLL映射到进程的地址空间中,以便可以调用导出的函数。

    现在我需要挥挥手了,因为这很棘手。封送拆收器构造堆栈帧,设置需要传递给导出函数的参数。这需要低级别的代码,小心地从窥探的眼睛中排除。从表面上看,它执行封送处理类支持的转换类型,以便在托管类型和非托管类型之间进行转换。这里,DllImportAttribute.CallingConvention属性很重要,因为它决定了需要将哪个参数值放在哪里,以便被调用的函数能够正确地读取它。

    接下来,它将设置SEH异常处理程序,以便捕获被调用代码引发的硬件异常并将其转换为托管异常。生成更常见的一个,AccessViolationException。还有其他人。

    接下来,它在堆栈上推送一个特殊的cookie,以指示非托管代码即将开始使用堆栈。这可以防止垃圾收集器误入非托管堆栈帧,并将在其中找到的指针解释为托管对象引用。您可以在调试器的调用堆栈中看到这个cookie,[托管到本机转换]。

    接下来,只是对GetProcAddress()函数地址的间接调用。使非托管代码运行。

        2
  •  8
  •   Michael Goldshteyn    14 年前

    非托管内存分配来自进程堆。您负责分配/解除分配内存,因为GC不知道这些对象,所以不会收集垃圾。

        3
  •  1
  •   Dave Black    12 年前

    正如一篇学术文章在这里所发布的信息一样:

    1. 加载程序堆:包含CLR结构和类型系统

    2. 低频堆:EEClass、ClassLoader和查找表

    3. GC Heap:用户为应用程序分配的专用堆内存

    4. JIT代码堆:mscoree(执行引擎)和JIT编译器为托管代码分配的内存

        4
  •  0
  •   Aliostad    14 年前

    你的问题有一部分是由迈克尔回答的。我回答另一部分。