C#托管内存与非托管内存之间的转换的实例讲解

c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存,然而c#毕竟运行在c++之上,有的时候,(比如可能我们需要引入一些第三方的c++或native代码的库,在Unity3d开发中很常见)我们需要直接在c#中操纵非托管的代码,这些non-managed memory我们就需要自己去处理他们的申请和释放了, c# 中提供了一些接口,完成托管和非托管之间的转换,以及对这部分内存的操作。

基本上有以下几种:

1.managed memory-> unmanaged memory

比如在c#中调用第三方的某个c++库,库中有个函数是void func(float * data, int length).我们需要传入给data的就应该是一个非托管的代码(why?首先传入托管的内存,c#层很可能会把它gc掉,而c++还在使用,而且托管的mem它的指针地址可能会发生改变,因此直接传给c++可能拿到的地址是错误的)

代码如下:

using System.Runtime.InteropServices;
float[] _managed_data =... // this is the c# managed data
GCHandle unmanaged_data_handle = GCHandle.Alloc(_managed_data, GCHandleType.Pinned); //这里将标记_managed_data暂时不能被gc回收,并且固定对象的地址
func(unmanaged_data_handle.AddrOfPinnedObject(),_managed_data.Length);//这里将拿到非托管内存的固定地址,传给c++
unmanaged_data_handle.Free();//使用完毕后,将其handle free,这样c#可以正常gc这块内存

2.un-managed memory->managed memory

在c++中返回一个un-managed mem给c#使用。有时需要在c++中分配一块处理好的内存,然后返回给c#来使用,如c++中某个接口 int func(int** data) (注意这里要使用指针的指针,因为data是得到的结果)

IntPtr unmanaged_ptr=IntPtr.Zero; //定义这个c#中用来接收c++返回数据的指针类型
int length = func(out unmanaged_ptr );//调用c++的函数,使unmanaged_ptr指向c++里分配的内存,注意这里用out ,才能与c++里面的**匹配。
byte[] managed_data = new byte[length];
Marshal.Copy(unmanaged_ptr, managed_data, 0, length);//将非托管内存拷贝成托管内存,才能在c#里面使用
Marshal.FreeHGlobal(unmanaged_ptr);//释放非托管的内存

3.在c#直接申请一个un-managed mem传给c++

有时需要直接在c#开辟一块非托管的内存,传给c++用,这块内存同样可以在c#中用后销毁。代码如下

IntPtr unmanaged_data_prt = Marshal. AllocHGlobal(100);// 直接分配100 byte的内存
func(unmanaged_data_prt);//传给c++使用
Marshal.FreeHGlobal(unmanaged_data_prt);使用后销毁非托管内存

此外 Marshal类里面还有很多处理非托管内存的方法。

备注

托管内存和非托管内存在c#里面可以互相自由的转化,主要通过Marshal类和GCHandle类,编程时只要注意非托管的内存一定要负责好释放就可以了。感谢大家对我们的支持。

(0)

相关推荐

  • C#托管内存与非托管内存之间的转换的实例讲解

    c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存,然而c#毕竟运行在c++之上,有的时候,(比如可能我们需要引入一些第三方的c++或native代码的库,在Unity3d开发中很常见)我们需要直接在c#中操纵非托管的代码,这些non-managed memory我们就需要自己去处理他们的申请和释放了, c# 中提供了一些接口,完成托管和非托管之间

  • C#使用stackalloc分配堆栈内存和非托管类型详解

    目录 stackalloc 表达式 stackalloc 分配 System.Span<T> 或 System.ReadOnlySpan<T> 类型 stackalloc 分配 指针类型 stackalloc分配内存的注意点 非托管类型 Unmanaged type stackalloc 表达式 stackalloc表达式在栈(stack)上分配内存块. 在方法执行期间创建的栈中分配的内存块会在方法返回时自动丢弃.不能显式释放使用 stackalloc 分配的内存.stackall

  • 详解C# 托管资源和非托管资源

    托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等.这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法.默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源. 在

  • C#中托管DLL和非托管DLL的区别详解

    首先解释一下,托管DLL和非托管DLL的区别.狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件.非托管DLL不是在Dotnet环境生成的DLL文件. 托管DLL文件,可以在Dotnet环境通过 "添加引用" 的方式,直接把托管DLL文件添加到项目中.然后通过 Using DLL命 名空间,来调用相应的DLL对象 .  非托管DLL文件,在Dotnet环境应用时,通过 DllImport 调用. C# 调用非托管DLL文件.DLL文件是用C语言编写的. 托管DLL就是能够在公共

  • Python3进制之间的转换代码实例

    Python3进制之间的转换 在Python里面实现进制之间的转换是非常方便的,有专门的函数来进行这个操作: 下面直接上代码: # 进制之间的转换 a = 10 # 转换为二进制 print(bin(a)) # 结果为0b1010 # 转换为八进制 print(oct(a)) # 结果为0o12 # 转换为八进制 print(hex(a)) # 结果为0xa # 一个非十进制的数转换为十进制 print(int(0b1010)) # 结果为10 以上就是本文的全部内容,希望对大家的学习有所帮助,

  • c#关于非托管内存的释放问题及解读

    目录 关于非托管内存的释放问题 托管内存与非托管内存之间的转换 1.managed memory-> unmanaged memory 2.un-managed memory->managed memory 3.在c#直接申请一个un-managed mem传给c++ 总结 关于非托管内存的释放问题 硬件:大华sdk 软件平台:win10+vs2015 背景:近期在做大华工业相机SDK的采集的时候,用到Marshal.copy,将托管的代码转换成非托管的指针内存,由于没有及时释放内存指针,导致

  • .net非托管资源的回收方法

    本文实例讲述了.net非托管资源的回收方法,分享给大家供大家参考.具体分析如下: 释放未托管的资源有两种方法   1.析构函数 2.实现System.IDisposable接口   一.析构函数  构造函数可以指定必须在创建类的实例时进行的某些操作,在垃圾收集器删除对象时,也可以调用析构函数.析构函数初看起来似乎是放置释放未托管资源.执行一般清理操作的代码的最佳地方.但是,事情并不是如此简单.由于垃圾回收器的运行规则决定了,不能在析构函数中放置需要在某一时刻运行的代码,如果对象占用了宝贵而重要的

  • C#(.Net)将非托管dll嵌入exe中的实现

    目录 托管dll与非托管dll 下载与安装 添加Dll 调用 编译 托管dll与非托管dll 托管dll实际上是指C#编写的dll,可以直接右键"引用"导入 而大部分情况下,我们需要引用C++写的dll,如果你的dll是使用 DllImport来导入的,那么它就属于非托管dll,这种dll无法直接嵌入exe中,需要借助工具:Costura.Fody,该工具可以使用VS直接下载 下载与安装 右键引用,选择"管理NuGet程序包",搜索 "fody"

  • 浅谈十进制小数和二进制小数之间的转换

    一.二进制数转换成十进制数 由二进制数转换成十进制数的基本做法是,把二进制数首先写成加权系数展开式,然后按十进制加法规则求和.这种做法称为"按权相加"法. 二.十进制数转换为二进制数 十进制数转换为二进制数时,由于整数和小数的转换方法不同,所以先将十进制数的整数部分和小数部分分别转换后,再加以合并. 1. 十进制整数转换为二进制整数 十进制整数转换为二进制整数采用"除2取余,逆序排列"法.具体做法是:用2去除十进制整数,可以得到一个商和余数:再用2去除商,又会得到一

  • 带你复习c# 托管和非托管资源

    前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存有限啊,这里面就牵扯到数据释放. 看下c# 的垃圾回收是怎么样的. 了解垃圾回收之前首先要了解数据,了解数据需要了解数据类型啊,数据类型分为值类型还有引用类型. windows 使用一个虚拟寻址系统,该系统把程序可用的内存地址映射到硬件内存中的实际地址上,这些任务完全由windows 在后台管理.我

随机推荐