Лучший способ обработать выделение памяти в C?

В конце концов я обнаружил, что причиной segfault было мое присоединение к пулу потоков из основного потока после вызова thread_pool.apply_async. Я удалил операторы close и join, и прямое соединение по сигналу работало нормально, как и ожидалось. Я продолжал получать предупреждение:

QObject::setParent: Cannot set parent, new parent is in a different thread

Но программа работала, как и ожидалось. Спасибо!

13
задан Jonas 7 April 2009 в 15:09
поделиться

11 ответов

Часть беспорядка - то, что это по сути более трудно в C. malloc и free подобны new и delete: malloc выделяет новую память и возвращает указатель на ту память. free делает ту память доступной снова, пока это - память, которая была выделена с помощью malloc. Иначе это просто делает хеш некоторого блока памяти. Это не заботится.

Важная вещь с malloc/free состоит в том, чтобы выбрать и последовательно поддерживать дисциплинированное использование. Вот некоторые подсказки:

ВСЕГДА проверяйте возвращенный указатель от malloc для ПУСТОГО УКАЗАТЕЛЯ

if((p = (char *) malloc(BUFSIZ)) == NULL {
   /* then malloc failed do some error processing. */
}

Для пояса и безопасности подтяжек, установленной в NULL указатель после освобождения его.

free(p);
p = NULL ;

попробуйте к malloc и освободите блок памяти в том же объеме если возможный:

 {  char * p ;
   if((p = malloc(BUFSIZ)) == NULL {
       /* then malloc failed do some error processing. */
   }

 /* do your work. */

   /* now you're done, free the memory */

   free(p);
   p = NULL ;  /* belt-and suspenders */
 }

Когда Вы не можете, прояснить, что то, что Вы возвращаете, malloc'память редактора, таким образом, вызывающая сторона может освободить его.

 /* foo: do something good, returning ptr to malloc memory */
 char * foo(int bar) {
     return (char *) malloc(bar);
 }
19
ответ дан 1 December 2019 в 17:55
поделиться

При записи этого я понял, что это - больше вопрос обо мне понимающий поток C, чем что-либо еще, но один вопрос за один раз.

Я честно думаю, что необходимо читать на K&R, если Вы не имеете.

10
ответ дан 1 December 2019 в 17:55
поделиться

К сожалению, существуют ограниченные стратегии автоматизации выделения памяти и освобождения в C. Компилятор C++ генерирует много кода негласно для Вас - он отслеживает каждую переменную на стеке и удостоверяется, что соответствующий деструктор называют, когда стек очищен. Это - на самом деле довольно сложный тип генерации кода, особенно когда Вы выдаете исключения в соединение.

C, с другой стороны, намного более просто, который является, почему это иногда называют "ассемблером высокого уровня". C не имеет никакого механизма, чтобы гарантировать, что конкретный бит кода называют, когда функция выходит, или переменная выталкивается от стека, так Вам решать для отслеживания каждый бит памяти, которую Вы выделяете, и каждый файл или сеть снабжают Вас сокетом, открываются и очищают их в соответствующей точке. Нет никакого практического способа создать автоматический интеллектуальный указатель в C.

Одно понятие, на которое необходимо посмотреть, является "пулами памяти". В основном, скорее та попытка отслеживать каждый отдельный блок памяти, которую Вы выделяете, Вы создаете пул, сделайте некоторый блок работы, поместив каждый блок памяти, который Вы выделяете в пул, затем освобождаете целый пул, когда Вы сделаны. Вы обмениваете определенную производительность и управляете здесь для упрощения познавательной нагрузки на программиста, но большую часть времени это определенно стоит того.

Необходимо посмотреть на Apache Портативный проект Во время выполнения. У них есть библиотека пула памяти (документы по http://apr.apache.org/docs/apr/1.3/group__apr__pools.html). Если APR слишком много, чтобы Вы погрузились в, можно реализовать очень простой пул памяти с помощью трех функций и структуры данных связанного списка. Псевдокод был бы чем-то как:

struct Pool {
  void* memoryBlock;
  struct Pool *next;
}

struct Pool *createPool(void) {
  /* allocate a Pool and return it */
}

void addToPool(struct Pool *pool, void *memoryBlock) {
  /* create a new Pool node and push it onto the list */
}

void destroyPool(struct Pool *pool) {
  /* walk the list, free each memory block then free its node */
}

Используя пул что-то вроде этого:

int main(void) {
  struct Pool *pool = createPool();
  /* pool is empty */

  doSomething(pool);

  /* pool full of crap, clean it up and make a new one */
  destroyPool(pool);
  pool = createPool();
  /* new pool is empty */

  doMoreStuff(pool);
  destroyPool(pool);

  return 0;
}
7
ответ дан 1 December 2019 в 17:55
поделиться

Печальная истина - то, что C действительно не разработан для инкапсуляции всех тех проблем управления памятью.

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

Это не обязательно изящно, но я не думаю, что существует много способов сделать это действительно изящным, не моделируя ООП в C.

6
ответ дан 1 December 2019 в 17:55
поделиться

Хорошо в C необходимо сделать все Вы управление памятью вручную, поскольку Вы уже обнаружили. Это должно не быть удивительно.

2
ответ дан 1 December 2019 в 17:55
поделиться

Обычный путь

MyType *ptr = malloc(array_size * sizeof *ptr);

Но если Вы хотите быть совместимыми с C++, сделать

MyType *ptr = (MyType*) malloc(array_size * sizeof *ptr);

Можно также сделать макрос

#define MALLOC( NUMBER, TYPE ) ( TYPE * ) malloc( NUMBER * sizeof( TYPE ) )
MyType *ptr = MALLOC(10, MyType);

Конечно, без RAII, удостоверьтесь когда-то позже, что Вы имеете

free(ptr);
0
ответ дан 1 December 2019 в 17:55
поделиться

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

Только вещь у Вас должно быть достаточно дисциплины, чтобы сделать управление.

Класс C++:

class foo {
public:
   ofstream ff;
   int x,y;
   foo(int _x) : x(_x),y(_x){ ff.open("log.txt"); }
   void bar() { ff<<x+y<<endl; }
};

int main()
{
   auto_ptr<foo> f(new foo);
   f->bar();
}

C объект

typedef struct FOO {
    FILE *ff;
    int x,y;
} *foo_t;

foo_t foo_init(int x)
{
   foo_t p=NULL;
   p=malloc(sizeof(struct FOO)); // RAII
   if(!p) goto error_exit;
   p->x=x; p->y=x;
   p->ff=fopen("log.txt","w");   // RAII
   if(!p->ff) goto error_exit;
   return p;
error_exit:   // ON THROW
   if(p) free(p);
   return NULL;
}

void foo_close(foo_t p)
{
   if(p) fclose(p->ff);
   free(p);
}

void foo_bar(foo_t p)
{
   fprintf(p->ff,"%d\n",p->x+p->y);
}

int main()
{
  foo_t f=foo_init(1);
  if(!f) return 1;
  foo_bar(f);
  foo_close(f);
  return 0;
}
-2
ответ дан 1 December 2019 в 17:55
поделиться

Один путь I "скрывает" выделение памяти, и освобождение должно выдать его к пользовательским контейнерам. Передайте контейнер объект un-malloced. Позвольте ему волноваться о malloc и когда я удалю объект, которому позволяют это волноваться о свободном. Конечно, это только работает, если Вы только храните объект в одном контейнере. Если у меня будут ссылки на объект повсеместно, то я создам эквивалент конструктора и методов деструктора с синтаксисом C:

 glob* newGlob(); 
 void freeGlob(glob* g);

(объектом я имею в виду что-либо, на что Вы указали бы на - не объекты C++).

1
ответ дан 1 December 2019 в 17:55
поделиться

Я не совсем уверен, что Вы спрашиваете, но C довольно прост:

struct Foo *f0 = malloc(sizeof(*f));   // alloc uninitialized Foo struct
struct Foo *f1 = calloc(1,sizeof(*f)); // alloc Foo struct cleared to all zeroes

//You usually either want to clear your structs using calloc on allocation, or memset. If 
// you need a constructor, just write a function:
Foo *Foo_Create(int a, char *b)
{
   Foo *r = calloc(1,sizeof(*r));
   r->a = a;
   r->b = strdup(b);
   return r;
}

Here is a simple C workflow with arrays:
struct Foo **foos = NULL;
int n_foos = 0;
...
for(i = 0; i < n_foos; ++i)
{
   struct Foo *f = calloc(1,sizeof(*f));
   foos = realloc(foos,sizeof(*foos)*++n_foos); // foos before and after may be different
   foos[n_foos-1] = f;
}

Если Вы становитесь необычными, можно записать макросы для помощи:

#define MALLOCP(P) calloc(1,sizeof(*P)) // calloc inits alloc'd mem to zero

Несколько точек:

  • malloc, calloc, перевыделение, и т.д. все бесплатное использование (), так управление этими вещами легки. Просто будьте последовательны.
  • производительность для mallocs может быть медленной. Кто-то отправил ссылку на это выше. В эти дни быстрые многопоточные выделения являются ключевыми, см. tcmalloc и др. Вы, вероятно, не должны волноваться об этом.
  • на современной архитектуре виртуальной памяти почти никогда не перестанет работать malloc, если Вы не будете вне виртуального адресного пространства. Если это происходит, переключатель к 64 битам ;)
  • Удостоверьтесь, что Вы используете систему, которая имеет проверку границ, вытер свободные значения, отслеживание утечки и весь этот хороший материал (см. valgrind, win32 "куча" отладки, и т.д.),
0
ответ дан 1 December 2019 в 17:55
поделиться

Существует много, можно сделать для создания жизни легче. Вы уже, кажется, пришел в голову идею создать фабрики/конструкторов для Ваших C-объектов. Это - хорошее начало, следуют ему.

Некоторые другие идеи рассмотреть.

  1. не соглашайтесь на стандарт malloc/free., идут, ища лучший, это было opensourced или пишет тот, что комплекты использование памяти объектов, которые Вы создаете. также, мы говорим C здесь, Вы собираетесь перезаписать свои объекты, свободные больше и однажды и забыть освобождать некоторых, поэтому встройте некоторую поддержку отладки в свою запись malloc., что Ваше собственное не твердо, если Вы не можете найти тот, который удовлетворяет Ваши потребности.

  2. используйте больше чем одну "кучу". используйте один в классе объекта, Вы создаете, используете временную "кучу", если Вы знаете Вас, Вы собираетесь иметь большое количество временных объектов, которые связаны, это подавляет фрагментацию памяти и позволяет Вам управлять памятью согласно использованию.

  3. взгляд на стратегии как пулы Objective C

  4. если Вы думаете, что понимаете, как C++ работает, то добавление поведения конструктора к выделению памяти на объектной фабрике не настолько трудно сделать, и использование сделанного на заказ свободного может затем предоставить Вам возможность назвать деструктор на объекте, являющемся free'd предоставление Вас назад часть поведения C++, которое Вы любили

1
ответ дан 1 December 2019 в 17:55
поделиться

Я не знаю, как скрыть их и как автоматизировать вещи.

C и C++ являются различными языками. Теперь, скажите что сто раз себе. Будьте громкими.

Что Вы подразумеваете под сокрытием? Что делает Вы подразумеваете, автоматизируют? Можно ли отправить некоторые примеры? Почему необходимо скрыть и/или автоматизировать.

Хорошие места онлайн для начинаний с выделением памяти C:

1
ответ дан 1 December 2019 в 17:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: