2013-05-11 59 views
2

我是C#的新手。最近當我更新應用程序(vs2008)時,我遇到了以下問題。C++/C#數組內存異常

應用程序有C++函數幫手如下:

array<float>^ Variant::CopyToFloats() 
{ 
    unsigned int n = this->data_uint8->Length; 
    array<float>^ dst = gcnew array<float>(n); //<<OutOfMemoryException happened here 
    for (unsigned int i = 0; i < n; i++) 
    dst[i] = (float)this->data_uint8[i]; 
    return dst; 
} 

在C#中的文件,

for(int i=0; i<m; i++) 
    { for(int j=0; j<n; j++) 
     { 
     float[] scan = data[i].CopyToFloats(); 
     for(int k=0; k<nn; k++) 
      sample[k]=scan[function(i,j)]; 
     } 
    } 

當我運行應用程序,OutOfMemoryException異常情況發生。

然後添加以下代碼

Process proc = Process.GetCurrentProcess(); 
    long memory = proc.PrivateMemorySize64; 

之前和外環後,我發現掃描的存儲器未釋放。

我嘗試以下方法:

1.清除掃描,並將其設置爲null,有/無使用GC.Collect的()

for(int i=0; i<m; i++) 
{ for(int j=0; j<n; j++) 
    { 
    float[] scan = data[i].CopyToFloats(); 
    for(int k=0; k<nn; k++) 
     sample[k]=scan[function(i,j)]; 
    } 
    Array.Clear(scan, 0, scan.Length); 
    scan = null; 
    //GC.Collect(); 
} 

隨着調用GC.Collect的(),程序跑得很慢。 沒有調用,程序仍然崩潰爲OOME。

我想知道哪些內存沒有發佈?掃描或陣列由gcnew創建?

2.由於數組大小很大(> 500000),我在進入循環之前分配大尺寸數組。

float[] scan = new float[data[0].GetSize()]; 
    for(int i=0; i<m; i++) 
    { for(int j=0; j<n; j++) 
     { 
      scan = data[i].CopyToFloats(); 
      for(int k=0; k<nn; k++) 
      sample[k]=scan[function(i,j)]; 
     } 
    } 

但OOME仍然發生。從這裏開始,我確信由gcnew創建的數組的內存沒有被釋放。我對嗎? 如果我是對的,爲什麼它沒有發佈?有什麼辦法可以釋放這個內存嗎? 如果我不對,請給我一些建議,謝謝!

回答

1

也許會更容易不轉換整個數組浮動,但只投值需要

for(int i=0; i<m; i++) 
{ for(int j=0; j<n; j++) 
    { 
    byte[] scan = data[i]; 
    for(int k=0; k<nn; k++) 
     sample[k]=(float)scan[function(i,j)]; 
    } 
} 

它不直接回答你的問題,但可以消除使用太多內存

的需要
+0

感謝您的諮詢! – yongqiang 2013-05-11 21:42:39

1

您可能會遇到large object heap fragmentation。這可以解釋你得到的內存不足錯誤,但是我不確定如果你只分配相同大小的數組將會出現碎片。

帕維爾的建議只根據需要施放每個元素聽起來像是最好的選擇。如果這是不可能的,或者你的情況需要,則預先分配的大陣是一個好主意,但似乎是在您發佈的例子中的錯誤:你需要做的是這樣

float[] scan = new float[data[0].GetSize()]; 
for(int i=0; i<m; i++) 
{ for(int j=0; j<n; j++) 
    { 
     temp = data[i].CopyToFloats(); // you still allocate a new array here! 
     for(int k=0; k<nn; k++) 
     sample[k]=scan[function(i,j)]; // scan has not been updated! 
    } 
} 

而不是temp = data[i].CopyToFloats(); data[i].CopyToFloats(scan)。您需要更改C++函數的簽名才能使用預分配的數組。


一些額外的想法:

只是因爲當你創建一個新的數組的內存溢出的異常情況發生,這並不意味着該數組是泄漏資源。這個數組很有可能每次都被GC成功清理,但其他一些對象卻不是。

數據[]是Variant的Array,還是數據實際上是一個帶有indexer的自定義集合類?
如果是這樣,我會高度懷疑索引器是問題所在。

如果您使用GC.WaitForPendingFinalizers()而不是GC.Collect(),程序是否會在沒有崩潰的情況下運行?
如果是這樣,那麼你的問題是一個終結器堵塞終結器線程的對象。如果新對象的創建速度比它們可以定稿更快,則會發生這種情況。每個具有析構函數的C++/cli類都是這樣的候選人。

+0

您提到的錯誤是我的打字錯誤。我將其固定在我的帖子中。謝謝!! – yongqiang 2013-05-11 21:33:01

+0

該程序仍然在使用GC.WaitForPendingFinalizers()時崩潰。 – yongqiang 2013-05-11 21:42:06

+0

您更改打字錯誤的方式仍然不會重複使用相同的數組。 CopyToFloats每次都會創建一個新的數組。如果'scan'在其之前包含另一個數組並不重要,它將不會被重用或覆蓋,只是將參考'scan'指向哪個數組。您需要將要重用的數組作爲參數傳遞給CopyToFloats,而CopyToFloats必須使用該數組,而不是使用gcnew創建另一個數組。如果不更改C++ CopyToFloats函數,則不可能重用數組。 – HugoRune 2013-05-12 00:24:10