C#托管內(nèi)存與非托管內(nèi)存之間的轉(zhuǎn)換的實(shí)例講解
c#有自己的內(nèi)存回收機(jī)制,所以在c#中我們可以只new,不用關(guān)心怎樣delete,c#使用gc來清理內(nèi)存,這部分內(nèi)存就是managed memory,大部分時(shí)候我們工作于c#環(huán)境中,都是在使用托管內(nèi)存,然而c#畢竟運(yùn)行在c++之上,有的時(shí)候,(比如可能我們需要引入一些第三方的c++或native代碼的庫,在Unity3d開發(fā)中很常見)我們需要直接在c#中操縱非托管的代碼,這些non-managed memory我們就需要自己去處理他們的申請(qǐng)和釋放了, c# 中提供了一些接口,完成托管和非托管之間的轉(zhuǎn)換,以及對(duì)這部分內(nèi)存的操作。
基本上有以下幾種:
1.managed memory-> unmanaged memory
比如在c#中調(diào)用第三方的某個(gè)c++庫,庫中有個(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#來使用,如c++中某個(gè)接口 int func(int** data) (注意這里要使用指針的指針,因?yàn)閐ata是得到的結(jié)果)
IntPtr unmanaged_ptr=IntPtr.Zero; //定義這個(gè)c#中用來接收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#開辟一塊非托管的內(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)化,主要通過Marshal類和GCHandle類,編程時(shí)只要注意非托管的內(nèi)存一定要負(fù)責(zé)好釋放就可以了。感謝大家對(duì)腳本之家的支持。
相關(guān)文章
c# 將Datatable數(shù)據(jù)導(dǎo)出到Excel表格中
本文主要介紹了c# 將Datatable數(shù)據(jù)導(dǎo)出到Excel表格中的方法。具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-03-03Winform?控件優(yōu)化LayeredWindow無鋸齒圓角窗體
這篇文章主要為大家介紹了Winform?控件優(yōu)化LayeredWindow實(shí)現(xiàn)無鋸齒圓角窗體示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09C#實(shí)現(xiàn)的Windows剪貼板監(jiān)視器功能實(shí)例【附demo源碼下載】
這篇文章主要介紹了C#實(shí)現(xiàn)的Windows剪貼板監(jiān)視器功能,結(jié)合實(shí)例形式分析了C#實(shí)現(xiàn)剪貼板監(jiān)視功能所涉及的相關(guān)Windows API函數(shù)與使用技巧,需要的朋友可以參考下2016-08-08Unity3D實(shí)現(xiàn)鼠標(biāo)控制旋轉(zhuǎn)轉(zhuǎn)盤
這篇文章主要為大家詳細(xì)介紹了Unity3D實(shí)現(xiàn)鼠標(biāo)控制旋轉(zhuǎn)轉(zhuǎn)盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02c#通過app.manifest使程序以管理員身份運(yùn)行
通常我們使用c#編寫的程序不會(huì)彈出這個(gè)提示,也就無法以管理員身分運(yùn)行。微軟的操作系統(tǒng)使用微軟的產(chǎn)品方法當(dāng)然是有的,通過app.manifest配置可以使程序打開的時(shí)候,彈出UAC提示需要得到允許才可以繼續(xù),這樣就獲得了管理員的權(quán)限來執(zhí)行程序2015-01-01