2

我是 C# 的新手。最近当我更新一个应用程序(vs2008)时,我遇到了以下问题。

该应用程序具有 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;

在外循环前后,发现scan的内存没有释放。

我尝试了以下方法:

1.清除扫描并将其设置为空,有/没有使用 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 创建的数组的内存没有被释放。我对吗?如果我是对的,为什么它没有发布?有什么办法可以释放这段记忆吗?如果我说的不对,请给我一些建议,谢谢!

4

2 回答 2

1

您可能会遇到大型对象堆碎片。这可以解释你得到的内存不足错误,但我不确定如果你只分配相同大小的数组,碎片会如何发生。

Pavel 建议只根据需要投射每个元素,这听起来像是最佳选择。如果在您的情况下这是不可能或不希望的,那么预分配大数组是一个好主意,但您发布的示例中似乎存在一个错误:

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++ 函数的签名才能使用预分配的数组。


一些额外的想法:

仅仅因为在创建新数组时发生 OutOfMemory 异常,这并不意味着该数组是泄漏资源。很有可能每次 GC 都成功地清理了数组,但其他一些对象却没有。

data[] 是一个变体数组,还是 data 实际上是一个带有索引器的自定义集合类?
如果是这样,我会高度怀疑索引器是问题所在。

GC.WaitForPendingFinalizers()如果您使用而不是,程序是否运行而不会崩溃GC.Collect()
如果是这样,那么您的问题是某个对象的终结器阻塞了终结器线程。如果新对象的创建速度快于它们最终确定的速度,就会发生这种情况。每个带有析构函数的 C++/cli 类都是该类的候选者。

于 2013-05-11T21:11:50.350 回答
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)];
   }
}

它不会直接回答您的问题,但可以消除使用过多内存的需要

于 2013-05-11T19:25:29.463 回答