c#应用程序中托管堆和本机堆的区别是什么?
本文关键字:区别 是什么 本机 应用程序 | 更新日期: 2023-09-27 17:54:48
From this http://blogs.msdn.com/b/visualstudioalm/archive/2014/04/02/diagnosing-memory-issues-with-the-new-memory-usage-tool-in-visual-studio.aspx
- Managed:对于托管应用程序,分析器默认情况下只收集托管堆信息。托管堆分析是通过在分析器中捕获一组CLR ETW事件来完成的。
- Native:对于本机应用程序,分析器只收集本机堆信息。为了收集本机堆信息,我们启用了堆栈跟踪和堆跟踪收集(ETW),这非常冗长,并将创建大型诊断文件。
我的问题是在我的c#程序(我只有c#代码与xaml文件)什么类型的对象将去托管堆和什么类型去本地堆?当我的应用程序运行时,我如何指定每个堆的最大大小?我假设GC只在托管堆上运行,对吗?
当您使用c#中的new操作符(或任何其他CLR语言中的相应操作符)创建对象时,. net运行时在"托管堆"(即由。net运行时管理的堆+垃圾收集器)中分配内存。实际上,这是两个堆中的一个——一个用于小于85K大小的对象,另一个用于大于85K大小的对象(大型数组等)。无论哪种方式,当分配这样一个对象时,您都不会像在本机代码中那样得到一个描述已分配空间地址的真实指针。你得到的是一个"句柄",它代表了到那个内存地址的间接连接。这种间接存在是因为实际的内存位置可能在GC收集和压缩堆时发生变化。
当你想与需要指针的非托管/本机代码对话时,你需要使用指针,而不是句柄。net提供了两种方法来将。net句柄转换为可以传递给非托管代码的原始指针。
- 使用Marshal在NT(或本机或非托管)堆上分配内存。AllocHGlobal或Marshal。AllocCoTaskMem并使用固定块或IntPtr。ToInt32/ToInt64获取底层指针。一定要调用Marshal. freehglobal/Marshal。FreeCoTaskMem自己或非托管代码释放内存正确(FreeAlloc/CoTaskMemFree在Windows上)。
- 如果你的数据是易被篡改的(这可能是与本地代码互操作时的情况),那么你可以简单地用GCHandle固定这个托管数据。Alloc,然后用从GCHandle获得的原始指针调用到本机代码。AddrOfPinnedObject,完成后释放固定(使用GCHandle.Free)。你也可以获得托管对象的实际底层指针地址,并在c#中临时固定在一个"固定"块中。
我希望这对你有帮助!