C - Можете ли вы освободить отдельные адреса памяти массива, выделенного динамически? - PullRequest
0 голосов
/ 04 января 2019

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

Ответы [ 5 ]

0 голосов
/ 04 января 2019

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

Вы, кажется, признаете, что ответ "нет", потому что вы выполняете с

Почему вы не можете освободить отдельный адрес, потому что пространство должно быть непрерывным?

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

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

если аргумент не совпадает с указателем, ранее возвращенным функцией управления памятью, или если пространство было освобождено при вызове free или realloc, поведение не определено.

Таким образом, free() показывает UB, если его аргумент является указателем на внутреннюю часть выделенного блока.

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

Кроме того, учтите, что, хотя вы не можете освободить определенные фрагменты большего выделения, вы можете использовать realloc(), чтобы уменьшить размер выделения (что может также включать его перемещение).

Все, что находится за ее пределами, относится к области поведения, специфичного для реализации, но имейте в виду, что

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

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

и если это ответ, то почему на жестких дисках происходит фрагментация

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

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

0 голосов
/ 04 января 2019

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

Стандарт C определяет услуги, предоставляемые malloc, free, realloc и соответствующими подпрограммами. Единственные условия, которые он дает для освобождения места, - это использование free для освобождения выделения и использование realloc для замены выделения на меньшее.

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

Если бы была потребность в такой услуге, ее можно было бы написать. Но программы и алгоритмы с годами развивались для использования существующих сервисов, и, похоже, нет особой необходимости выделять отдельные части выделений. Как правило, если программа собирается работать со многими объектами, которые она может освободить по отдельности, она распределяет их по отдельности. Это часто встречается при построении структур данных всех видов, использовании указателей для построения деревьев, хэшированных массивов списков или других структур и так далее. Структуры данных часто состоят из отдельных узлов, которые могут быть выделены или освобождены индивидуально. Таким образом, нет необходимости вырезать отдельные куски, которые будут выделяться из больших ассигнований.

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

0 голосов
/ 04 января 2019

Распределение памяти обрабатывается как, казалось бы, непрерывные блоки памяти (хотя может и не быть в физической памяти, но это не имеет значения).

Нет простого способа «вырезать дыру» в одном выделении памяти, но вы можете сделать что-то вроде этого:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARRAY_LEN 11

int main (void)
{
    char *array;

    array = (char *) malloc(ARRAY_LEN);
    strcpy(array,"0123456789");

    printf("%s\n",array);

    //Remove the 5th element:
    memmove(&array[5], &array[5+1], ARRAY_LEN-5);
    array = realloc(array, ARRAY_LEN-1);
    printf("%s\n",array);

    free(array);
    return 0;
}

Некоторые файловые системы Linux допускают «пробивание дырок» в файлах, поэтому с файлом mmap вы можете использовать системный вызов fallocate, используя его как массив в памяти.

0 голосов
/ 04 января 2019

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

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

В противном случае нет. Интерфейс free определен так, чтобы принимать только адреса, возвращенные с malloc, calloc или realloc.

Почему вы не можете освободить отдельные адреса, потому что пространство должно быть непрерывным?

Что ж, прямой ответ заключается в том, что для этого не определен интерфейс. Невозможно сказать free, сколько указателя, который вы передали, должен быть освобожден. Если вы хотите освободить всю память до конца выделенного блока, realloc сделает это.

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

и если это ответ, то почему на жестких дисках происходит фрагментация

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

|---File 1---|--- Hole ---|---File 3---|

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

|---File 1---|---File 4...|---File 3---|...File 4---|

Это происходит на «жестких дисках», потому что файловая система спроектирована таким образом: позволяет большому файлу перекрывать доступные дыры на физическом носителе.

Диск RAM, используемый для файловой системы, также может в конечном итоге иметь фрагментированные файлы.

Несмежную структуру данных можно рассматривать как «фрагментированную», например, связанный список или дерево, но это предусмотрено проектом. Массив считается смежным по самому определению. Однако файлы в файловой системе не являются массивами.

0 голосов
/ 04 января 2019

Первый вопрос НЕТ, поскольку вы можете освободить только всю память, выделенную одной функцией семейства malloc

Фрагментация жестких дисков не имеет ничего общего с распределением памяти.

...