C#托管內(nèi)存與非托管內(nèi)存之間的轉(zhuǎn)換的實(shí)例講解
c#有自己的內(nèi)存回收機(jī)制,所以在c#中我們可以只new,不用關(guān)心怎樣delete,c#使用gc來(lái)清理內(nèi)存,這部分內(nèi)存就是managed memory,大部分時(shí)候我們工作于c#環(huán)境中,都是在使用托管內(nèi)存,然而c#畢竟運(yùn)行在c++之上,有的時(shí)候,(比如可能我們需要引入一些第三方的c++或native代碼的庫(kù),在Unity3d開(kāi)發(fā)中很常見(jiàn))我們需要直接在c#中操縱非托管的代碼,這些non-managed memory我們就需要自己去處理他們的申請(qǐng)和釋放了, c# 中提供了一些接口,完成托管和非托管之間的轉(zhuǎn)換,以及對(duì)這部分內(nèi)存的操作。
基本上有以下幾種:
1.managed memory-> unmanaged memory
比如在c#中調(diào)用第三方的某個(gè)c++庫(kù),庫(kù)中有個(gè)函數(shù)是void func(float * data, int length).我們需要傳入給data的就應(yīng)該是一個(gè)非托管的代碼(why?首先傳入托管的內(nèi)存,c#層很可能會(huì)把它gc掉,而c++還在使用,而且托管的mem它的指針地址可能會(huì)發(fā)生改變,因此直接傳給c++可能拿到的地址是錯(cuò)誤的)
代碼如下:
using System.Runtime.InteropServices; float[] _managed_data =... // this is the c# managed data GCHandle unmanaged_data_handle = GCHandle.Alloc(_managed_data, GCHandleType.Pinned); //這里將標(biāo)記_managed_data暫時(shí)不能被gc回收,并且固定對(duì)象的地址 func(unmanaged_data_handle.AddrOfPinnedObject(),_managed_data.Length);//這里將拿到非托管內(nèi)存的固定地址,傳給c++ unmanaged_data_handle.Free();//使用完畢后,將其handle free,這樣c#可以正常gc這塊內(nèi)存
2.un-managed memory->managed memory
在c++中返回一個(gè)un-managed mem給c#使用。有時(shí)需要在c++中分配一塊處理好的內(nèi)存,然后返回給c#來(lái)使用,如c++中某個(gè)接口 int func(int** data) (注意這里要使用指針的指針,因?yàn)閐ata是得到的結(jié)果)
IntPtr unmanaged_ptr=IntPtr.Zero; //定義這個(gè)c#中用來(lái)接收c++返回?cái)?shù)據(jù)的指針類型 int length = func(out unmanaged_ptr );//調(diào)用c++的函數(shù),使unmanaged_ptr指向c++里分配的內(nèi)存,注意這里用out ,才能與c++里面的**匹配。 byte[] managed_data = new byte[length]; Marshal.Copy(unmanaged_ptr, managed_data, 0, length);//將非托管內(nèi)存拷貝成托管內(nèi)存,才能在c#里面使用 Marshal.FreeHGlobal(unmanaged_ptr);//釋放非托管的內(nèi)存
3.在c#直接申請(qǐng)一個(gè)un-managed mem傳給c++
有時(shí)需要直接在c#開(kāi)辟一塊非托管的內(nèi)存,傳給c++用,這塊內(nèi)存同樣可以在c#中用后銷毀。代碼如下
IntPtr unmanaged_data_prt = Marshal. AllocHGlobal(100);// 直接分配100 byte的內(nèi)存 func(unmanaged_data_prt);//傳給c++使用 Marshal.FreeHGlobal(unmanaged_data_prt);使用后銷毀非托管內(nèi)存
此外 Marshal類里面還有很多處理非托管內(nèi)存的方法。
備注
托管內(nèi)存和非托管內(nèi)存在c#里面可以互相自由的轉(zhuǎn)化,主要通過(guò)Marshal類和GCHandle類,編程時(shí)只要注意非托管的內(nèi)存一定要負(fù)責(zé)好釋放就可以了。感謝大家對(duì)腳本之家的支持。
相關(guān)文章
unity實(shí)現(xiàn)方向盤轉(zhuǎn)動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了unity實(shí)現(xiàn)方向盤轉(zhuǎn)動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
教你創(chuàng)建一個(gè)帶診斷工具的.NET鏡像
本文編寫(xiě)的初衷是因?yàn)樵谌豪镉泻芏嘈』锇橛龅缴a(chǎn)環(huán)境性能問(wèn)題的時(shí)候,.NET的runtime鏡像中沒(méi)有帶一些工具,安裝和使用起來(lái)很麻煩,所以分享一些我們公司內(nèi)部一些技巧,對(duì).NET鏡像帶診斷工具相關(guān)知識(shí)感興趣的朋友一起看看吧2022-07-07
淺談C#2.0泛型中的變化:default關(guān)鍵字
下面就詳細(xì)的說(shuō)明一下。之所以會(huì)用到default關(guān)鍵字,是因?yàn)樾枰诓恢李愋蛥?shù)為值類型還是引用類型的情況下,為對(duì)象實(shí)例賦初值2013-09-09
C# Dynamic之:ExpandoObject,DynamicObject,DynamicMetaOb的應(yīng)用(下)
本篇文章是對(duì)C#中ExpandoObject,DynamicObject,DynamicMetaOb的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
自定義實(shí)現(xiàn)Json字符串向C#對(duì)象轉(zhuǎn)變的方法
自定義實(shí)現(xiàn)Json字符串向C#對(duì)象轉(zhuǎn)變的方法,需要的朋友可以參考一下2013-03-03
NGUI實(shí)現(xiàn)滑動(dòng)翻頁(yè)效果實(shí)例代碼
本文通過(guò)一段實(shí)例代碼給大家介紹NGUI實(shí)現(xiàn)滑動(dòng)翻頁(yè)效果,代碼簡(jiǎn)單易懂,對(duì)ngui 滑動(dòng)翻頁(yè)相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-04-04

