2013-05-11 4 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.Clear сканирование и установить его в нулевое значение, с/без использования 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.As размер массива большой (> 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

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++, чтобы использовать предварительно выделенный массив.


некоторые дополнительные идеи:

Просто потому, что OutOfMemory Исключение происходит, когда вы создаете новый массив, это не означает, что массив является утечка ресурсов. Вполне возможно, что массив успешно очищается GC каждый раз, но какой-то другой объект нет.

Является ли data [] Array of Variant, или данные фактически являются пользовательским классом коллекции с indexer?
Если это так, я бы очень сомневался, что указателем будет проблема.

Выполняется ли программа без сбоев, если вы используете GC.WaitForPendingFinalizers() вместо GC.Collect()?
Если это так, то ваша проблема - это какой-то объект с финализатором, засоряющим поток финализатора. Это произойдет, если новые объекты будут созданы быстрее, чем они могут быть завершены. Каждый класс C++/cli с деструктором является кандидатом на это.

+0

Ошибка, о которой вы говорили, это моя ошибка ввода. Я исправил это в своем посте. Благодаря!! – yongqiang

+0

Программа по-прежнему работает с крахом с использованием GC.WaitForPendingFinalizers(). – yongqiang

+0

То, как вы изменили ошибку ввода, по-прежнему не использует повторно один и тот же массив. CopyToFloats каждый раз будет создавать новый массив. Не имеет значения, если перед этим 'scan' содержал еще один массив, он не будет повторно использоваться или перезаписан, вы только изменяете, на какой массив ссылаются« сканирование ». Вам нужно передать массив, который вы хотите повторно использовать в качестве параметра CopyToFloats, а CopyToFloats должен использовать этот массив вместо создания другого с gcnew. Повторное использование массива невозможно без изменения функции C++ CopyToFloats. – HugoRune

Смежные вопросы