C управление памятью

Убедитесь, что JUnit.jar находится в вашем пути к классу, а затем вызовите бегун из командной строки из консоли

java org.junit.runner.JUnitCore [имя тестового класса]

Ссылка: junit FAQ

86
задан Chris Hanson 2 September 2008 в 01:54
поделиться

12 ответов

Существует два места, куда переменные могут быть помещены в память. Когда Вы создаете переменную как это:

int  a;
char c;
char d[16];

переменные создаются в" стек ". Переменные стека автоматически освобождены, когда они выходят из объема (то есть, когда код не может больше достигать их). Вы могли бы услышать их, назвал "автоматические" переменные, но это вышло из моды.

Много примеров новичка будут использовать только переменные стека.

стек хорош, потому что это автоматически, но это также имеет два недостатка: (1) компилятор должен знать заранее, насколько большой переменные, и (b), стековое пространство несколько ограничено. Например: в Windows, при настройках по умолчанию для компоновщика Microsoft, стек установлен на 1 МБ, и не все это доступно для Ваших переменных.

, Если Вы не знаете во время компиляции, насколько большой Ваш массив, или если Вам нужны большой массив или структура, Вам нужен "план B".

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

int size;
// ...
// Set size to some value, based on information available at run-time. Then:
// ...
char *p = (char *)malloc(size);

(Отмечают, что переменными в "куче" не управляют непосредственно, но через указатели)

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

free(p);

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

В C и C++, Вы ответственны для чистки переменных "кучи" как показанный выше. Однако существуют языки и среды, такие как Java и языки.NET как C#, которые используют другой подход, где "куча" очищена самостоятельно. Этот второй метод, названный "сборкой"мусора"", намного легче на разработчике, но Вы платите штраф в издержках и производительности. Это - баланс.

(я замял много деталей для предоставления более простого, но надо надеяться более выровненный ответ)

221
ответ дан Euro Micelli 5 November 2019 в 15:36
поделиться

Вот пример. Предположим, что у Вас есть strdup () функция, которая копирует строку:

char *strdup(char *src)
{
    char * dest;
    dest = malloc(strlen(src) + 1);
    if (dest == NULL)
        abort();
    strcpy(dest, src);
    return dest;
}

И Вы называете его как это:

main()
{
    char *s;
    s = strdup("hello");
    printf("%s\n", s);
    s = strdup("world");
    printf("%s\n", s);
}

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

Это не грандиозное предприятие для этого небольшого количества памяти, но рассмотрите случай:

for (i = 0; i < 1000000000; ++i)  /* billion times */
    s = strdup("hello world");    /* 11 bytes */

Вы теперь израсходовали 11 ГБ памяти (возможно больше, в зависимости от Вашего диспетчера памяти) и если Вы не отказали, Ваш процесс, вероятно, работает довольно медленно.

Для фиксации необходимо назвать свободным () для всего, что получено с malloc () после того, как Вы заканчиваете использовать его:

s = strdup("hello");
free(s);  /* now not leaking memory! */
s = strdup("world");
...

Hope этот пример помогает!

17
ответ дан Mark Harrison 5 November 2019 в 15:36
поделиться

Я думаю самый краткий способ ответить на вопрос в рассмотреть роль указателя в C. Указатель является легким весом все же мощный механизм, который дает Вам огромную свободу за счет огромной возможности выстрелить себе в ногу.

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

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

выделение "кучи" менее свойственно на язык. Это - в основном ряд вызовов библиотеки, который предоставляет Вам владение блока памяти данного размера, пока Вы не готовы возвратиться ('свободный') это. Это звучит простым, но связано с невыразимым горем программиста. Проблемы являются простыми (освобождение той же памяти дважды, или нисколько [утечек памяти], не выделения достаточной памяти [переполнение буфера], и т.д.), но трудными избежать и отладить. Очень дисциплинированный подход абсолютно обязателен в practive, но конечно язык на самом деле не передает под мандат его.

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

5
ответ дан Bill Forster 5 November 2019 в 15:36
поделиться

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

 char *string = malloc(stringlength); // stringlength is the number of bytes to allocate

 // Do something with the string...

 free(string); // Free the allocated memory
9
ответ дан Jeremy Ruten 5 November 2019 в 15:36
поделиться

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

пример:

int main() {
    char* myString = (char*)malloc(5*sizeof(char));
    myString = "abcd";
}

В этой точке Вы выделили 5 байтов для myString и заполнились, это с "abcd\0" (представляет конец в виде строки в пустом указателе - \0). Если бы Ваше строковое выделение было

myString = "abcde";

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

4
ответ дан Chris B-C 5 November 2019 в 15:36
поделиться

Также Вы могли бы хотеть использовать динамическое выделение памяти, когда необходимо определить огромный массив, сказать интервал [10000]. Вы не можете только поместить его в стек, потому что тогда, гм... Вы получите переполнение стека.

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

2
ответ дан Serge 5 November 2019 в 15:36
поделиться

(Я пишу, потому что я чувствую, что ответы до сих пор не находятся вполне на метке.)

причина Вы имеете к управлению памятью, которое стоит упомянуть, когда у Вас есть проблема / решение, которое требует, чтобы Вы создали сложные структуры. (Если Ваши программы отказывают, если Вы выделяете для много интервала на стеке сразу, это - ошибка.) Как правило, структура First Data, которую необходимо будет изучить, является некоторым список . Вот единственный связанный, первое, что пришло на ум:

typedef struct listelem { struct listelem *next; void *data;} listelem;

listelem * create(void * data)
{
   listelem *p = calloc(1, sizeof(listelem));
   if(p) p->data = data;
   return p;
}

listelem * delete(listelem * p)
{
   listelem next = p->next;
   free(p);
   return next;
}

void deleteall(listelem * p)
{
  while(p) p = delete(p);
}

void foreach(listelem * p, void (*fun)(void *data) )
{
  for( ; p != NULL; p = p->next) fun(p->data);
}

listelem * merge(listelem *p, listelem *q)
{
  while(p != NULL && p->next != NULL) p = p->next;
  if(p) {
    p->next = q;
    return p;
  } else
    return q;
}

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

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

Получают хороший отладчик... Удачи!

2
ответ дан Anders Eurenius 5 November 2019 в 15:36
поделиться

Euro Micelli

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

0
ответ дан Community 5 November 2019 в 15:36
поделиться

Ted Percival :
... Вы не должны бросать malloc () возвращаемое значение.

Вы корректны, конечно. Я полагаю, что это всегда было верно, хотя у меня нет копии K& R для проверки.

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

Это особенно вероятно, если Ваш компилятор понимает комментарии в стиле С++.

Да... Вы поймали меня там. Я провожу намного больше времени в C++, чем C. Спасибо за то, чтобы замечать это.

0
ответ дан Community 5 November 2019 в 15:36
поделиться

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

a. Вы хотите, чтобы переменная пережила функции, и Вы не хотите иметь глобальную переменную. исключая:

struct pair{
   int val;
   struct pair *next;
}

struct pair* new_pair(int val){
   struct pair* np = malloc(sizeof(struct pair));
   np->val = val;
   np->next = NULL;
   return np;
}

b. Вы хотите динамично выделить память. Наиболее распространенным примером является массив без фиксированной длины:

int *my_special_array;
my_special_array = malloc(sizeof(int) * number_of_element);
for(i=0; i

c. You want to do something REALLY dirty. For example, I would want a struct to represent many kind of data and I don't like union (union looks soooo messy):

struct data{ int data_type; long data_in_mem; }; struct animal{/*something*/}; struct person{/*some other thing*/}; struct animal* read_animal(); struct person* read_person(); /*In main*/ struct data sample; sampe.data_type = input_type; switch(input_type){ case DATA_PERSON: sample.data_in_mem = read_person(); break; case DATA_ANIMAL: sample.data_in_mem = read_animal(); default: printf("Oh hoh! I warn you, that again and I will seg fault your OS"); }

Видят, длинного значения достаточно для содержания ЧЕГО-ЛИБО. Просто не забудьте освобождать его, или Вы будете сожалеть. Это среди моих любимых приемов, чтобы весело провести время в C: D.

Однако обычно, Вы хотели бы избегать своих любимых приемов (T ___ T). Вы повредите свою ОС, рано или поздно при использовании их слишком часто. Пока Вы не используете *выделение и свободный, безопасно сказать, что Вы являетесь все еще девственными, и что код все еще выглядит хорошим.

0
ответ дан magice 5 November 2019 в 15:36
поделиться

Уверенный. Если Вы создаете объект, который существует за пределами объема, Вы используете его в. Вот изобретенный пример (примите во внимание, что мой синтаксис будет выключен; мой C ржав, но этот пример все еще проиллюстрирует понятие):

class MyClass
{
   SomeOtherClass *myObject;

   public MyClass()
   {
      //The object is created when the class is constructed
      myObject = (SomeOtherClass*)malloc(sizeof(myObject));
   }

   public ~MyClass()
   {
      //The class is destructed
      //If you don't free the object here, you leak memory
      free(myObject);
   }

   public void SomeMemberFunction()
   {
      //Some use of the object
      myObject->SomeOperation();
   }


};

В этом примере, я использую объект типа SomeOtherClass в течение времени жизни MyClass. Объект SomeOtherClass используется в нескольких функциях, таким образом, я динамично выделил память: объект SomeOtherClass создается, когда MyClass создается, несколько раз используется по жизни объекта, и затем освобождается, как только MyClass освобожден.

, Очевидно, если бы это было реальным кодом, не было бы никакой причины (кроме возможно потребления стековой памяти) для создания myObject таким образом, но этот тип создания объекта / разрушение становится полезным, когда Вы имеете много объектов и хотите точно управлять, когда они создаются и уничтожаются (так, чтобы Ваше приложение не сосало выше на 1 ГБ RAM в течение его всего времени жизни, например), и в Оконной среде, это в значительной степени обязательно, как возражает, что Вы создаете (кнопки, скажите), должен существовать хорошо за пределами какой-то конкретной функции (или даже класс) объем.

-2
ответ дан TheSmurf 5 November 2019 в 15:36
поделиться

Вещь помнить состоит в том, чтобы всегда инициализировать Ваши указатели на ПУСТОЙ УКАЗАТЕЛЬ, так как неинициализированный указатель может содержать псевдослучайный действительный адрес памяти, который может совершить ошибки указателя идти вперед тихо. Путем осуществления указателя, который будет инициализирован с ПУСТЫМ УКАЗАТЕЛЕМ, можно всегда ловить при использовании этого указателя, не инициализируя его. Причина состоит в том, что операционные системы "соединяют виртуальный адрес 0x00000000 проводом" к общим исключениям нарушения защиты для захвата использования нулевого указателя.

4
ответ дан Hernán 24 November 2019 в 07:56
поделиться
Другие вопросы по тегам:

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