Начинающий программист здесь. Это может быть нонсенс.
Я узнал о некоторых основах динамического распределения памяти с помощью malloc
и free
. Когда я выделяю память, для конкретности скажем, для массива из 10 ints
через malloc
, malloc
возвращает мне указатель p на начало выделенного блока памяти. Обычно я хотел бы передать этот указатель, а также некоторые соответствующие метаданные о выделении памяти (а именно, что это был массив длиной 10 int
s) в остальную часть моего кода для поддержки последующего информированного и безопасного чтения/записи. доступ. Именно это я и делаю, перемещая эти метаданные по своему коду.
Мне интересно, что когда приходит время действительно освобождать память, free
вполне способен выполнять эту работу, имея только указатель p; это не нужно говорить, например. длина массива. Я не знаю никаких подробностей здесь, но из того, что я прочитал, реализации malloc
/free
включают хранение и доступ к метаданным, которые записываются рядом с каждым распределением, и доступ к этим метаданным осуществляется free
в время освобождения (и, очевидно, достаточное, чтобы точно знать, какие ячейки памяти должны быть освобождены). Я предполагаю, что это должно означать, в частности, что в моем примере длина выделенного массива целых чисел может быть получена из метаданных, которые ищет free
.
Это приводит меня к нескольким вопросам:
Верны ли высокоуровневые подробности моего понимания существования этих метаданных?
Может ли программист, использующий стандартную библиотеку, получить доступ к этим метаданным распределения?
Если нет, можно ли легко получить к нему доступ из c средствами, отличными от стандартной библиотеки?
Если ответ на 2 или 3 отрицательный по причинам, связанным со стандартами и правилами, существуют ли конкретные контексты или примеры (например, которые работают только на определенной ОС или с определенной нестандартной реализацией c и т. д.), где это возможно и/или полезно?
Если это плохая идея, независимо от того, возможно ли это, мне было бы любопытно услышать, почему. Мое единственное предположение на данный момент заключается в том, что детали того, как хранятся метаданные, могут различаться в зависимости от системы, поэтому наивно использующий их код может оказаться нетерпимым к системным изменениям. Тем не менее, учитывая, что free может успешно использовать его в разных системах, я думаю, что будет способ инкапсулировать системные зависимости, чтобы по-прежнему получать полезный самоанализ метаданных.
Для 2 или 3 я представляю что-то вроде:
// Allocate some memory
int size = 10;
int *arr;
arr = (int *)malloc(sizeof(int) * size)
// Do other stuff.
// Choose not to keep track of storage details necessary for informed read/write access to arr, e.g. size;
// Acquire access to whatever `free` would access if asked to free `arr`
_type_ metadata = get_pointer_metadata(arr);
// Use metadata to perform read/writes
Но не знаете, есть ли что-то вроде get_pointer_metadata
в стандартной библиотеке c или в сторонних пакетах?
Я пробовал искать в Google такую функцию, но мое понимание деталей ситуации и языка слишком плохое, чтобы делать осмысленные поиски.
Нет надежного способа получить доступ к метаданным, поддерживаемым malloc()
et al. Следовательно, не рекомендуется пытаться получить к нему доступ. Однако во многих системах есть заголовок <malloc.h>
, который обеспечивает элементарный доступ к метаданным. Этим заголовком часто злоупотребляют — его следует использовать не для получения доступа к malloc()
(используйте для этого <stdlib.h>
), а скорее к функции mallinfo()
. Даже это ограничено, потому что оно не сообщает обо всех возможных выделениях памяти — см. man mallinfo
в Linux.
Имеет смысл. Спасибо вам всем. Мое единственное продолжение, @JonathanLeffler. Как можно согласиться There is no reliable way to access the metadata maintained by malloc()
с тем фактом, что реализация(и) бесплатного, кажется, делает это надежно? Вы просто говорите, что нет надежного способа сделать это в разных реализациях malloc? Или бесплатно также не надежен в получении соответствующих метаданных?
Для этого нет задокументированного внешнего интерфейса (кроме mallinfo()
того, о котором я упоминал). То, как библиотека делает что-то за кулисами, — это ее проблема; ему не нужно раскрывать свою грязную внутреннюю работу широкой публике, и он этого не делает. Заменить malloc()
непросто — нужно заменить calloc()
, realloc()
, free()
, и это как минимум. Эти функции должны понимать друг друга — они не должны сообщать вам, как они понимают друг друга.
Я не считаю ваш вопрос ерундой, я задавался вопросом о подобных вещах, в частности о том, как ОС решает, где и сколько места выделять на вызов, и почему появляется free, чтобы не отдавать память сразу. (На самом деле это так, но при просмотре метрик использования памяти кажется, что это не так.) FWIW, здесь есть некоторое обсуждение внутренней работы того, как работает распределение памяти
@JonathanLeffler Понятно, имеет смысл, большое спасибо за ваше терпение и помощь. Я, конечно, понимаю, что такие вещи не обязаны выставляться на всеобщее обозрение, и низкая мотивация делать это, особенно если они грязные, но я надеялся, что этот аспект внутренностей не такой уж грязный и может быть разоблачен. Мне просто любопытно и я пытаюсь учиться, на самом деле я не собираюсь пытаться работать таким образом для доступа к метаданным с учетом ваших отзывов, если это неясно.
@Это рекреационный совет; Избегайте ошибок распределения и упрощайте: arr = (int *)malloc(sizeof(int) * size)
--> arr = malloc(sizeof arr[0] * size)
.
Имеет смысл, спасибо за совет (и ответ) @chux-ReinstateMonica
Возможно/рекомендуется ли доступ к метаданным, хранящимся в malloc, через стандартную библиотеку?
Нет. Стандартная библиотека C не предлагает такого доступа.
Метаданные существуют, но то, где и что существует, более разнообразно. Метаданные могут быть закодированы в самом указателе. Исходный размер выделения может не существовать.
Нет.
Возможно. Некоторые компиляторы/библиотеки предлагают такой доступ. Это зависит от реализации.
Да, есть конкретные примеры. Поскольку я кодирую для переносимости, я не использую их, а вместо этого сам код отслеживает соответствующие метаданные.
Идея не столько плохая, сколько слабая.
Метаданные часто зависят от реализации, и поэтому, если бы библиотека требовала доступа к ним, это заставляло бы реализацию следовать ограничительной модели памяти.
Вместо того, чтобы внедрять конкретные решения, рассмотрите возможность создания структуры с вашими метаданными и передачи ее.
typedef struct {
void *ptr;
size_t size;
} ptr_sz;
Разные
malloc
будут делать это по-разному, и могут даже быть разные форматы метаданных, разные выделения из одного и того же распределителя (подумайте о 16-байтовой паре указателей и многокилобайтном буфере), поэтому нет переносимого способа сделать это.