Освобождение статических структур в библиотеке C - PullRequest
2 голосов
/ 19 апреля 2011

Проект, над которым я работаю, включает летательный аппарат с кодом GNC, написанным в библиотеке C (.out).Мы должны вызывать этот C-код из LabVIEW (основного программного обеспечения для авионики) в виде библиотеки .out, и природа программного обеспечения требует статических указателей для хранения данных между последовательными вызовами функции.Мы вызываем исполнительную функцию GNC через регулярные промежутки времени на протяжении полета.Сейчас я пытаюсь вызвать эту функцию, используя оболочку Matlab MEX в DLL на Windows, и это выявило некоторые проблемы управления памятью.

Я объявляю структуры в начале функции следующим образом:

static Nav_str *Nav_IN_OUT_ptr;
static  hguid_ref *Guid_IN_OUT_ptr;
static  HopControl *Control_IN_OUT_ptr;

Nav_IN_OUT_ptr = (Nav_str *)malloc(sizeof(Nav_str));
Guid_IN_OUT_ptr = (hguid_ref *)malloc(sizeof(hguid_ref));
Control_IN_OUT_ptr = (HopControl *)malloc(sizeof(HopControl));

Это происходит при каждом запуске функции.Однако после того, как эта функция вызывается несколько раз итеративно, она всегда вылетает из-за ошибки сегментации памяти после попытки выхода.Насколько я понимаю, эта память должна была очиститься, не так ли?

Чтобы очистить ее вручную, я добавил эти строки в конец, которые будут вызываться только на итерации очистки:

free(Nav_IN_OUT_ptr);
free(Guid_IN_OUT_ptr);
free(Control_IN_OUT_ptr);

Это правильный способ освободить эту память?Могу ли я освободить эту память?Может ли существовать другая причина ошибки сегментации, кроме того, что C неправильно не выделяет память после последнего вызова или Matlab неправильно управляет своей памятью?Я все время искал человека с похожей проблемой (даже связывался с Mathworks) без особой удачи, поэтому любые комментарии или предложения будут высоко оценены.

Ответы [ 3 ]

3 голосов
/ 19 апреля 2011

Если освободить память, это не приведет к ошибке сегментации.Вероятно, ваша проблема лежит где-то еще.Два вероятных условия:

  1. Переполнение буфера
  2. Использование указателя на ранее освобожденную память.
  3. Использование неверного значения указателя, каким-то образомустановлен неправильно.
  4. Попытка освободить указатель, не возвращенный malloc'd (или уже free'd)

Насколько я понимаю, эта память предполагаласьчтобы очистить себя, это неправильно?

Да, вам нужно вызвать free(), чтобы освободить память обратно в кучу.Я бы также предложил установить значение указателя на null после освобождения, это может помочь вам поймать условие 2 сверху.


Nav_IN_OUT_ptr = (Nav_str *)malloc(sizeof(Nav_str));

Это утверждение кода сомнительно.Что такое Nav_str тип?Вы уверены, что не хотите использовать strlen(Nav_str)+1?


Мне также нужно спросить, какова цель сделать ваши указатели статичными?Переменные статических функций в основном глобальные, и используются только в редких случаях.

2 голосов
/ 19 апреля 2011

Ваш код имеет утечку памяти - он выделяет эту память каждый раз, когда вызывается функция.Даже у вашего текущего метода все еще есть утечка памяти - если вы вызовете free() только один раз, на последней итерации, то вы освободите только самое последнее выделение.

Однако утечка памяти обычно не вызываетошибка сегментации (если ваша утечка памяти не исчерпает всю доступную память, вызывая последующие malloc() вызовы для возврата NULL).

Если вы хотите иметь статические структуры, которые выделяются только один раз и используются повторно, вы делаетевообще не нужно использовать malloc() - вы можете просто изменить свои объявления на:

static Nav_str Nav_IN_OUT;
static hguid_ref Guid_IN_OUT;
static HopControl Control_IN_OUT;

... и использовать Nav_IN_OUT.field вместо Nav_IN_OUT_ptr->field и &Nav_IN_OUT вместо Nav_IN_OUT_ptr (если вы непосредственно передаете значение указателя другим функциям).

1 голос
/ 19 апреля 2011

Насколько я понимаю, эта память должна была очиститься, не так ли?

Извините, но вы ошиблись.:) Память, выделенная с помощью malloc(), будет сохраняться до тех пор, пока вы не удалите ее вручную с помощью free().(Вы действительно получили это правильно в конце концов. Ура.:)

Это правильный способ освободить эту память?Могу ли я освободить эту память?

То, что является правильным способом освобождения памяти, но может быть не в правильном месте .В общем, старайтесь писать свои звонки free() одновременно с написанием звонков malloc().

Может быть, вы выделяете в начале функции, а затем освобождаете в конце функции.(В этом случае использование памяти в стеке может быть лучше, если память когда-либо используется только функциями, вызываемыми исходной функцией.)

Возможно, у вас есть foo_init() функция, которая вызывает malloc() исоздает связанные контексты из API, затем вы передаете этот контекст в другие подпрограммы, которые работают с этими данными, а затем вам нужно поместить вызовы free() в foo_destroy() или foo_free() или аналогичную подпрограмму.Затем все ваши абоненты должны сбалансировать вызовы foo_init() и foo_free().Это было бы особенно уместно, если вы не можете просто написать вызовы foo_init() и foo_destroy() в одной функции;скажем, ваши объекты, возможно, должны быть удалены в некоторой случайной точке в более крупном цикле событий.

И, возможно, данные должны быть распределены один раз и жить вечно.Это было бы правильно для некоторых проектов приложений, и по именам переменных трудно сказать, должны ли эти блоки данных жить вечно.

Может быть, есть другая причина ошибки сегментации, кромеC не правильно отказался от памяти после последнего вызова, или Matlab неправильно управляет своей памятью?

Конечно, может быть;возможно, эта память возвращается слишком рано, возможно, какой-то указатель free() редактируется два или более раз, или вы перезаписываете свои буферы (этот вызов malloc(sizeof(Nav_str)) немного беспокоит; вероятно, он просто выделяет four или восемь байт, в зависимости от размера указателя на вашей платформе, и прежде чем заменить его на strlen(), обратите внимание, что strlen() не оставит место для байта NUL вконец строки; malloc(len+1); - это обычный шаблон для выделения памяти для строки, и меня беспокоит каждый раз, когда я не вижу, что +1 в вызове.)

Некоторое время с valgrind, несомненно, поможет найти ошибки памяти, и, возможно, какое-то время с Electric Fence может помочь.valgrind определенно новее и определенно может лучше обрабатывать «большие» программы (поскольку электрический забор будет выделять новую страницу для каждого malloc(), это может быть дорого).

...