Как программа узнает, сколько памяти освободить? - PullRequest
1 голос
/ 28 сентября 2011

Я подозреваю, что ответ на мой вопрос зависит от языка, поэтому я хотел бы знать о C и C ++. Когда я вызываю free() в буфере или использую delete[], как программа узнает, сколько памяти нужно освободить?

Где хранится размер буфера или динамически размещаемого массива и почему он также недоступен для программиста?

Ответы [ 7 ]

2 голосов
/ 28 сентября 2011

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

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

1 голос
/ 28 сентября 2011

Куча отслеживает все блоки памяти, как выделенные, так и свободные, специально для этой цели. Типичная (если наивная) реализация выделяет память, использует несколько байтов в начале для учета и возвращает адрес после этих байтов. При последующих операциях (free / realloc) было бы вычтено несколько байтов, чтобы попасть в область бухгалтерии.

Некоторые реализации кучи (скажем, Windows GlobalAlloc()) позволяют узнать размер блока с учетом начального адреса. Но в куче RTL C / C ++ такого сервиса нет.

Обратите внимание, что malloc () иногда перераспределяет память, поэтому информация о malloc размере блока будет иметь ограниченную полезность. C ++ new [] 'ed массивы, это совсем другое дело - для тех, кто знает, точный размер массива необходим для правильной работы уничтожения массива. Тем не менее, в C ++ нет такой вещи, как оператор dynamic_sizeof.

1 голос
/ 28 сентября 2011

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

Относительно вашего другого вопроса: почему ваше приложение должно знать об этом? Это не твоя забота. Он отделяет управление распределением памяти от приложения, поэтому вы можете использовать разные распределители (из соображений производительности или отладки).

0 голосов
/ 28 сентября 2011

Не путайте освобождение и уничтожение.

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

выражение-массив выражение delete[] arr; не только освобождает память, но и вызывает все деструкторы . Для этого недостаточно просто знать объем памяти, но нам также нужно знать количество элементов. Для этой цели new T[N] фактически выделяет больше , чем sizeof(T) * N байт памяти, поэтому средство удаления массивов знает, сколько деструкторов нужно вызвать. Вся эта память должным образом освобождается соответствующим оператором удаления.

0 голосов
/ 28 сентября 2011

Это не так сильно зависит от языка. Все это делает менеджер памяти.

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

0 голосов
/ 28 сентября 2011

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

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

0 голосов
/ 28 сентября 2011

Он хранится внутри, в зависимости от языка / компилятора / ОС.

Иногда он доступен (например, .Longth в C #), хотя это может относиться только к тому, сколько памяти вам разрешено использовать, а не к общему размеру объекта.

...