C 託管記憶體與非託管記憶體之間的轉換

2021-10-08 06:41:11 字數 3643 閱讀 6620

c#有自己的記憶體**機制,所以在c#中我們可以只new,不用關心怎樣delete,c#使用gc來清理記憶體,這部分記憶體就是managed memory,大部分時候我們工作於c#環境中,都是在使用託管記憶體,然而c#畢竟執行在c++之上,有的時候,(比如可能我們需要引入一些第三方的c++或native**的庫,在unity3d開發中很常見)我們需要直接在c#中操縱非託管的**,這些non-managed memory我們就需要自己去處理他們的申請和釋放了, c# 中提供了一些介面,完成託管和非託管之間的轉換,以及對這部分記憶體的操作。

基本上有以下幾種:

比如在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這塊記憶體

在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);

//釋放非託管的記憶體

有時需要直接在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類,程式設計時只要注意非託管的記憶體一定要負責好釋放就可以了。

c#有自己的記憶體**機制,所以在c#中我們可以只new,不用關心怎樣delete,c#使用gc來清理記憶體,這部分記憶體就是managed memory,大部分時候我們工作於c#環境中,都是在使用託管記憶體,然而c#畢竟執行在c++之上,有的時候,(比如可能我們需要引入一些第三方的c++或native**的庫,在unity3d開發中很常見)我們需要直接在c#中操縱非託管的**,這些non-managed memory我們就需要自己去處理他們的申請和釋放了, c# 中提供了一些介面,完成託管和非託管之間的轉換,以及對這部分記憶體的操作。

基本上有以下幾種:

比如在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這塊記憶體

在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);

//釋放非託管的記憶體

有時需要直接在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類,程式設計時只要注意非託管的記憶體一定要負責好釋放就可以了。

轉 C 託管記憶體與非託管記憶體之間的轉換

1.c 的託管 和非託管 c 有自己的記憶體 機制,所以在c 中我們可以只new,不用關心怎樣delete,c 使用gc來清理記憶體,這部分記憶體就是managed memory,大部分時候我們工作於c 環境中,都是在使用託管記憶體,然而c 畢竟執行在c 之上,有的時候,比如可能我們需要引入一些第三...

c 關於非託管記憶體的釋放問題

硬體 大華sdk 軟體平台 win10 vs2015 背景 近期在做大華工業相機sdk的採集的時候,用到marshal.copy,將託管的 轉換成非託管的指標記憶體,由於沒有及時釋放記憶體指標,導致pc的記憶體一直 通過檢視 之後發現是因為記憶體指標的原因,所以使用 marshal.freehglo...

C 託管資源與非託管資源

在.net 程式設計環境中,系統的資源分為託管資源和非託管資源。託管資源 net平台中,clr為程式設計師提供了一種很好的記憶體管理機制,使得程式設計師在編寫 時不要顯式的去釋放自己使用的記憶體資源 這些在先前c和c 中是需要程式設計師自己去顯式的釋放的 這種管理機制稱為gc garbage col...