2013-05-11 79 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