C 如何快速釋放記憶體的大陣列詳解

2022-09-26 01:33:09 字數 2822 閱讀 8977

本文告訴大家如何使用 marshal 做出可以快速釋放記憶體的大陣列。最近在做 3d ,需要不斷申請一段大記憶體陣列,然後就釋放他,但是 c# 對於大記憶體不是立刻釋放,所以就存在一定的效能問題。在部落格園看到了一位大神使用 marshal 做出快速申請的大陣列,於是我就學他的方法來弄乙個。本文程式設計客棧告訴大家這個類是如何使用。

在使用的時候,先來看下原來的 c# 的大陣列效能。可以看到在不停gc,效能不好

static void main(string args)

console.readkey();

} private static void foo()

在使用 lknudnmarshal 之前需要知道這是什麼,其實 marshal 就是乙個提供 com 互操作的方法。

下面使用乙個快速申請 int 陣列來告訴大家如何使用。

是否還記得 c 的申請陣列?其實下面的方法和 c 的相同

int n = 100000;//長度

intptr buffer = marshal.allochglobal(sizeof(int) * n);

這時就可以使用 buffer 作為陣列

下面對他的第 k 個元素修改

intptr buffer = marshal.allochglobal(sizeof(int) * n);

int k = 2;

intptr t = buffer + k * sizeof(int);

var p = marshal.ptrtostructure(t);

console.writeline("p " + p); //196713 這時的值是不確定

p = 2;

marshal.structuretoptr(p,t,false);

p = marshal.ptrtostructure(t);

console.writeline("p " + p);//2

//遍歷

console.writelknudnline("遍歷");

for (int i = 0; i < 10; i++)

遍歷:            43909312

4450214420

024

1357220181

196712

lknudn;      550912

543686656

可以從上面的**看到,主要使用的兩個方法是 structuretoptr 和 ptrtostructure ,而 structuretoptr 就是從指定型別寫到指標,希望大家還知道如何使用指標,ptrtostructure 就是從指標指向的地方開始讀資料,讀指定型別的資料。所以可以從 marshal 把乙個型別使用另乙個型別來讀取,但是一般需要讀取的型別都需要是確定型別大小的,如 char 可以、string 不可以。

反過來,structuretoptr 是對指定指標寫入指定的型別,同樣也是需要確定這個型別的大小,如可以寫入 char 但是不可以寫入 string。這就是對陣列讀寫的方法。

那麼遍歷的時候什麼輸出一些詭異的值,實際上因為沒有初始化,裡面的值是不確定的。我覺得用這個做隨機數也不錯。

使用 marshal 是比較安全,因為 ms 做了很多處理,但是也會讓程式閃退,如下面的**

private static void foo()

catch (exception e)

marshal.freehglobal(buffer);

}會出現異常 system.accessviolationexception,這個異常是無法 catch 的,所以使用的時候最好封裝一下

「system.accessviolationexception」型別的未經處理的異常在 未知模組

嘗試讀取或寫入受保護的記憶體。這通常指示其他記憶體已損壞

如果需要 catch 那麼請在 app.config 新增下面的**

<?xml version="1.0" encoding="utf-8" ?>

然後在 main 函式新增 handleprocesscorruptedstateexceptions ,請看**

[handleprocesscorruptedstateexceptions]

static void main(string args)

catch (exception e)

}console.writeline("完成");

console.readkey();

}這時可以看到進入 unhandledexception ,但是無法接住,軟體還是會崩潰

那麼如何釋放記憶體?因為這個申請是沒有經過管理的,如果沒有手動釋放,那麼就出現記憶體洩露。

static void main(string args)

console.readkey();

} private static void foo()

上面的**很快就可以看到記憶體占用到2g,所以需要手動釋放

marshal.freehglobal(buffer);

原來的 byte 陣列需要使用 1g 記憶體,而且速度很慢,而現在使用這個方法只需要 7m 記憶體,速度很快

所以在需要進行大陣列申請的時候,需要不停釋放,就可以使用這個方法。

如果想使用封裝好的,請看下面的大神弄好的類

參見:c#+無unsafe的非託管大陣列(large unmanaged array in c# without 『unsafe' keyword)

實際在哪些地方使用?實際上因為很多時候都是使用例項化池,但是例項化池在進入遊戲的時候,可以讓gc不會讓程式暫停,但是會在遊戲進入下一關的時候,無法快速清理資料。所以這時就可以使用 marshal 做例項化池,瞬間就可以清空。

上面的方法暫時不告訴大家如何做,因為涉及到公司的使用。

C 快速釋放記憶體的大陣列

使用marshal快速申請釋放大陣列。使用allochglobal 函式開闢空間 static void main string args console.readkey private static void foo 使用marshal申請記憶體是沒有經過管理的,如果沒有手動釋放,那麼就出現記憶體...

C 快速釋放記憶體的大陣列

本文告訴大家如何使用 marshal 做出可以快速釋放記憶體的大陣列。最近在做 3d 需要不斷申請一段大記憶體陣列,然後就釋放他,但是 c 對於大記憶體不是立刻釋放,所以就存在一定的效能問題。在看到了一位大神使用 marshal 做出快速申請的大陣列,於是我就學他的方法來弄乙個。本文告訴大家這個類是...

C 物件陣列釋放造成記憶體洩漏

物件陣列在釋放的時候,經常會遇到兩種情況,可能會造成記憶體洩漏 例如,geopoint是乙個類 class geopoint geopoint double x,double y geopoint public void setx double x void sety double y double...