Узнать размер выделенной памяти
Есть ли способ в C, чтобы узнать размер динамически распределенной памяти?
Есть ли способ узнать размер памяти, связанный с p ?
ОТВЕТЫ
Ответ 1
Q. Итак, могу ли я запросить пакет malloc , чтобы узнать, насколько большой выделенный блок является?
а. К сожалению, нет стандартного или переносного способа. (Некоторые компиляторы предоставляют нестандартные расширения.) Если вам нужно знать, вам придется самому отслеживать это. (См. Также вопрос 7.28.)
Ответ 2
Не существует стандартного способа найти эту информацию. Однако некоторые реализации предоставляют такие функции, как msize чтобы сделать это. Например:
- _msize в Windows
- malloc_size в MacOS
- malloc_usable_size в системах с glibc
Имейте в виду, однако, что malloc выделит минимум запрошенного размера, поэтому вы должны проверить, действительно ли msize-вариант для вашей реализации возвращает размер объекта или памяти, фактически выделенной в куче.
Ответ 3
C менталитет состоит в том, чтобы предоставить программисту инструменты, помогающие ему выполнять его работу, а не предоставлять абстракции, которые изменяют характер его работы. C также пытается избежать упрощения/повышения безопасности, если это происходит за счет предела производительности.
Некоторым вещам, которые вы могли бы сделать с областью памяти, требуется только расположение начала региона. К таким вещам относятся работа с нулевыми строками, управление первыми n байтами области (если область, как известно, по крайней мере такая большая) и т.д.
В основном, отслеживание длины области - это дополнительная работа, и если C сделал это автоматически, это иногда делалось бы без необходимости.
Для многих функций библиотеки (например, fread() ) требуется указатель на начало области, а также размер этой области. Если вам нужен размер региона, вы должны отслеживать его.
Да, реализации malloc() обычно отслеживают размер региона, но они могут делать это косвенно или округлять его до некоторой ценности или вообще не сохранять. Даже если они поддерживают его, поиск размера таким образом может быть медленным по сравнению с тем, чтобы отслеживать его самостоятельно.
Если вам нужна структура данных, которая знает, насколько велик каждый регион, C может сделать это за вас. Просто используйте структуру, которая отслеживает, насколько велика область, а также указатель на область.
Ответ 4
Нет, библиотека времени выполнения C не предоставляет такую функцию.
Некоторые библиотеки могут предоставлять функции, специфичные для платформы или компилятора, которые могут получить эту информацию, но в целом способ отслеживания этой информации находится в другой целочисленной переменной.
Ответ 5
Вот лучший способ, по которому я видел создание тега с указателем для хранения размера с адресом. Все функции указателя будут работать, как ожидалось:
Вы также можете реализовать оболочку для malloc и добавить теги (например, выделенный размер и другая метаинформация) перед указателем возвращен malloc. Это фактически метод, который компилятор С++ теги со ссылками на виртуальные классы. Вот один рабочий Пример:
Преимущество этого метода над структурой с размером и указателем
заключается в том, что вам нужно только заменить malloc и бесплатные вызовы. Все другие операции указателя не требуют рефакторинга.
Ответ 6
Как и все остальные уже сказали: "Нет".
Кроме того, я всегда буду избегать всех функций, связанных с конкретными производителями, потому что, когда вы обнаружите, что вам действительно нужно их использовать, это обычно признак того, что вы делаете это неправильно. Вы должны либо хранить размер отдельно, либо не знать об этом вообще. Использование функций поставщика - это самый быстрый способ потерять одно из основных преимуществ написания на C, переносимости.
Ответ 7
Я ожидаю, что это будет зависимым от реализации.
Если у вас есть структура данных заголовка, вы можете вернуть его на указатель и получить размер.
Ответ 8
Ответ 9
Если вы используете malloc, вы не можете получить размер.
С другой стороны, если вы используете OS API для динамического выделения памяти, например Windows функции кучи, тогда это можно сделать.
Ответ 10
Этот код, вероятно, будет работать на большинстве установок Windows:
Ответ 11
Это может сработать, небольшое обновление в вашем коде:
Но это приведет к 1, то есть памяти, связанной с p , если она char* . Если это int* , тогда результат будет равен 4.
Нет способа узнать общее распределение.
Ответ 12
Хорошо, теперь я знаю, что это не отвечает на ваш конкретный вопрос, но, думая, вне коробки, как бы. Это происходит со мной, вам, вероятно, не нужно знать. Ок, ок, нет, я не имею в виду, что у вас плохая или не ортодоксальная реализация. Я имею в виду, что вы, вероятно, (не глядя на свой код, я только догадываюсь), вы только хотите знать, могут ли ваши данные в выделенной памяти, если это так, то это решение может быть лучше. Он не должен предлагать слишком много накладных расходов и решит вашу "подходящую" проблему, если это действительно то, что вы обрабатываете:
или если вам нужно сохранить старое содержимое:
конечно, вы могли бы просто использовать:
и выполняться с ним.
Ответ 13
Все, кто говорит вам, что это невозможно, технически правильно (лучший вид правильно).
По техническим причинам плохая идея полагаться на подсистему malloc для точного определения размера выделенного блока. Чтобы убедиться в этом, представьте, что вы писали большое приложение с несколькими различными распределителями памяти - возможно, вы используете raw libc malloc в одной части, но operator new C++ operator new в другой части, а затем какой-то конкретный Windows API в еще одной часть. Итак, у вас есть все виды void* летающих вокруг. Написание функции, которая может работать с любым из этих void* невозможно, если вы не можете каким-то образом определить по значению указателя, из какой кучи это произошло.
Таким образом, вы можете захотеть заключить каждый указатель в вашей программе в какое-то соглашение, которое указывает, откуда пришел указатель (и куда его нужно вернуть). Например, в C++ мы называем это std::unique_ptr<void> (для указателей, которые должны быть operator delete 'd) или std::unique_ptr<void, D> (для указателей, которые должны быть возвращены через какой-то другой механизм D ). Вы можете сделать то же самое в C, если хотите. И как только вы в любом случае заключаете указатели в более крупные и безопасные объекты, это всего лишь маленький шаг для struct SizedPtr < void *ptr; size_t size; >struct SizedPtr < void *ptr; size_t size; >struct SizedPtr < void *ptr; size_t size; >и тогда вам больше не нужно беспокоиться о размере выделения.
Тем не мение.
Существуют также веские причины, по которым вы можете на законных основаниях знать фактический базовый размер выделения. Например, возможно, вы пишете инструмент профилирования для своего приложения, который будет сообщать о фактическом объеме памяти, используемой каждой подсистемой, а не только об объеме памяти, который, по мнению программиста, он использовал. Если каждое из ваших 10-байтовых распределений тайно использует 16 байтов под капотом, это хорошо знать! (Конечно, будут и другие издержки, которые вы не измеряете таким образом. Но есть и другие инструменты для этой работы.) Или, может быть, вы просто исследуете поведение realloc на своей платформе. Или, может быть, вы хотите "округлить" потенциал растущего распределения, чтобы избежать преждевременного перераспределения в будущем. Пример:
- Visual Studio, Win64 - _msize
- GCC/Clang, glibc, Linux - malloc_usable_size
- Clang, libc, Mac OS X - malloc_size
- Clang, jemalloc, Mac OS X - работает на практике, но я бы не стал доверять (молча смешивает jemalloc malloc и нативный libc malloc_size )
- Должно работать нормально с jemalloc на Linux
- Должно нормально работать с dlmalloc в Linux, если скомпилировано без USE_DL_PREFIX
- Должно работать везде с tcmalloc
Ответ 14
int *a; a=malloc(n*sizeof(int)); если malloc возвращает NULL, это означает, что вы не получили память, иначе вы получите базовый адрес назначенного блока, то есть размер блока (n*sizeof(int)) .
Ответ 15
Quuxplusone писал: "Написание функции, которая может работать с любым из этих void * s, невозможно, если вы не можете каким-то образом определить из значения указателя, из какой кучи это произошло". Определить размер динамически выделяемой памяти в C "
На самом деле в Windows _msize дает вам выделенный объем памяти от значения указателя. Если на адресе нет выделенной памяти, выдается ошибка.
есть ли способ В C узнать размер динамически выделенной памяти?
есть ли способ узнать размер памяти, связанной с p ?
Q. Поэтому я могу запросить malloc пакет, чтобы узнать, насколько большой выделенный блок?
A. К сожалению, нет стандартного или портативного способа. (Некоторые компиляторы предоставляют нестандартные расширения. Если вам нужно знать, вы должны будете следить за этим сами. (См. также вопрос 7.28.)
нет стандартного способа найти эту информацию. Однако некоторые реализации предоставляют такие функции, как msize для этого. Например:
- _msize на Windows
- malloc_size на MacOS
- malloc_usable_size на системах с glibc
имейте в виду, что malloc выделит минимум запрошенного размера, поэтому вы должны проверить, является ли вариант msize для вашего реализация фактически возвращает размер объекта или памяти, фактически выделенной в куче.
некоторые вещи, которые вы могли бы сделать с областью памяти, требуют только место старта регионе. Такие вещи включают работу с нулевыми строками, манипулируя первым n байт области (если известно, что область по крайней мере такая большая) и так далее.
в принципе, отслеживание длины области является дополнительной работой, и если C сделал это автоматически, иногда это будет делать это без необходимости.
многие библиотечные функции (например, fread() ) требует указатель на начало области, а также размер этой области. Если вам нужен размер региона, вы должны отслеживать его.
да, реализации malloc () обычно следите за размером региона, но они могут сделать это косвенно, или округлить его до некоторой ценности, или не держать его вообще. Даже если они поддерживают его, поиск размера таким образом может быть медленным по сравнению с отслеживанием его самостоятельно.
Если вам нужна структура данных, которая знает, насколько велика каждая область, C может сделать это за вас. Просто используйте структуру, которая отслеживает, насколько велика область, а также указатель на регион.
нет, библиотека времени выполнения C не предоставляет такой функции.
некоторые библиотеки могут предоставлять функции, специфичные для платформы или компилятора, которые могут получить эту информацию, но обычно способ отслеживать эту информацию находится в другой целочисленной переменной.
Как все уже говорили: Нет, нет.
кроме того, я бы всегда избегал всех функций, специфичных для поставщика, потому что, когда вы обнаружите, что вам действительно нужно их использовать, это обычно признак того, что вы делаете это неправильно. Вы должны либо хранить размер отдельно, либо не знать его вообще. Использование функций поставщика-Это самый быстрый способ потерять одно из основных преимуществ написания на C, переносимость.
вот лучший способ, который я видел, чтобы создать указатель с тегами для хранения размера с адресом. Все функции указателя будут работать так, как ожидалось:
вы также можете реализовать оболочку для malloc и бесплатно добавлять теги (например, выделенный размер и другая метаинформация) перед указателем вернулся Мэллок. Это фактически метод, который компилятор C++ объекты теги ссылки на виртуальные классы. Вот один работает пример:
преимущество этого метода над структурой с размером и указатель
это то, что вам нужно только заменить malloc и бесплатные звонки. Все другие операции указателя не требуют рефакторинга.
Я ожидал бы, что это будет зависеть от реализации.
Если вы получили структуру данных заголовка, вы можете вернуть ее на указатель и получить размер.
Если вы используете malloc, то вы не можете получить размер.
С другой стороны, если вы используете OS API для динамического выделения памяти, например Windows функции кучи, тогда это возможно сделать.
этот код, вероятно, будет работать на большинстве установок Windows:
это может сработать, небольшое обновление в вашем коде:
но это приведет к 1, то есть памяти, связанной с p если это char* . Если это int* тогда результат будет 4.
нет никакого способа узнать общее распределение.
Ну, теперь я знаю,что это не ответ на ваш конкретный вопрос, однако мышление вне коробки, как это было. Мне пришло в голову, что вам, вероятно, не нужно знать. Хорошо, хорошо, нет, я не имею в виду, что у вас плохая или неортодоксальная реализация. Я имею в виду, что вы, вероятно (не глядя на свой код, я только догадываюсь), вы хотите знать, могут ли ваши данные поместиться в выделенную память, если это так, то это решение может быть лучше. Он не должен предлагать слишком много накладных расходов и решит вашу проблему "подгонки", если это действительно то, что вы обрабатываете:
или если вам нужно сохранить старое содержание:
конечно, вы можете просто использовать:
и покончим с этим.
все, кто говорит вам, что это невозможно, технически правильно (лучший вид правильного).
по техническим причинам, это плохая идея полагаться на подсистему malloc, чтобы точно сказать вам размер выделенного блока. Чтобы убедиться в этом, представьте, что вы пишете--21-->большой приложение, с несколькими различными распределителями памяти-возможно, вы используете raw libc malloc в одной части, но c++ operator new в другой части, а затем некоторые конкретные окна API в еще одной части. Итак, у вас есть все виды void* летают. Написание функции, которая может работать на любой из этих void* s невозможно, если вы не можете каким-то образом определить по значению указателя, из какой из ваших куч он пришел.
таким образом, вы можете обернуть каждый указатель в своей программе некоторым соглашением, которое указывает, откуда пришел указатель (и куда его нужно вернуть). Например, в C++ мы называем это std::unique_ptr<void> (для указателей, что нужно быть operator delete ' d) или std::unique_ptr<void, D> (для указателей, которые должны быть возвращены через некоторый другой механизм D ). Вы могли бы сделать то же самое в C, если вы хотели. И как только вы заворачиваете указатели в более безопасные объекты в любом случае, это всего лишь маленький шаг к struct SizedPtr < void *ptr; size_t size; >и тогда вам больше не нужно беспокоиться о размере распределения.
однако.
здесь и веские причины, почему вы могли бы законно хотите узнать фактический базовый размер распределения. Например, возможно, вы пишете инструмент профилирования для своего приложения, который будет сообщать фактический объем памяти используется каждой подсистемы, а не только объем памяти, что программист мысль он использовал. Если каждое из ваших 10-байтовых распределений тайно использует 16 байтов под капотом, это хорошо знать! (Конечно, будут и другие накладные расходы, которые вы не измеряете таким образом. Но есть еще другие инструменты для это работа.) Или, может быть, вы просто расследуете поведение realloc на вашей платформе. Или, может быть, вы хотели бы "округлить" способность растущего распределения, чтобы избежать преждевременное перераспределение в будущем. Пример:
Я столкнулся с какой-то проблемой, в этом случае вы можете понравиться своим идеям.
В этой программе его печать 4, что (char *) значение, но мне нужно, сколько байт, выделенных для
что.
Вы также можете реализовать оболочку для malloc и бесплатно добавлять теги (например, выделенный размер и другую метаинформацию) перед указателем, возвращаемым malloc. Это фактически метод, с помощью которого компилятор С++ теряет объекты со ссылками на виртуальные классы.
Вот один рабочий пример:
Преимущество этого метода над структурой с размером и указателем
заключается в том, что вам нужно только заменить malloc и бесплатные вызовы. Все остальные операции указателя не требуют рефакторинга.
ответил(а) 2016-02-11T00:37:00+03:00 5 лет, 9 месяцев назадНевозможно узнать, сколько памяти было выделено только указателем. do sizeof (p) получит размер переменной-указателя p , который он принимает во время компиляции, и который является размером указателя. То есть, память, которую принимает указательная переменная для хранения указательной переменной p . Внутри p сохраняется исходный адрес блока памяти.
Как только вы выделите некоторую память с помощью malloc , он вернет исходный адрес блока памяти, но конец блока не будет найден из него, так как для блока нет терминатора. Вы определяете конец блока, поэтому вам нужно идентифицировать его любыми способами, поэтому храните его где-нибудь. Поэтому вам нужно сохранить длину блока где-нибудь, чтобы узнать, где заканчивается блок, на который указывает p .
Примечание. Хотя структура распределения памяти отслеживает выделенные и нераспределенные блоки, поэтому мы можем знать выделенную длину блока памяти из этих структур, но эти структуры недоступны для использования пользователями, если какая-либо функция библиотеки не предоставляет их, Поэтому код с использованием такой функции не переносится (указывается @Rudy Velthuis). Поэтому лучше всего следить за структурой.
Хотя возможно, что некоторые библиотеки позволят вам определить размер выделенного буфера, это не будет стандартная функция C, и вы должны смотреть на свою библиотеку на собственные документы для этого.
Однако, если есть много мест, где вам нужно знать размер выделенной памяти, самый чистый способ сделать это - сохранить размер рядом с указателем. То есть:
Затем каждый раз, когда вы malloc указатель, вы также записываете размер в поле size . Однако проблема с этим методом заключается в том, что вы должны указывать указатель каждый раз, когда используете его. Если бы вы были на С++, я бы предложил использовать классы шаблонов. Однако и в этом случае это не сложно, просто создайте столько структур, сколько у вас есть. Так, например,
Учитывая похожие имена, как только вы определяете указатель, вам не нужны дополнительные усилия (например, кастинг) для доступа к массиву. Пример использования:
Насколько я помню, в POSIX такого не было. Но где-то было. Завтра. кх-м. уже сегодня до работы доберусь - поищу.
По-моему malloc и free определены (по крайней мере в GNU Libc) как weak. Даже не копаясь в потрохах Libc можно при каждом malloc(x) вызывать libc_malloc(x+sizeof(unsigned long)) и хранить размер выделенной памяти в конце блока, определить свой malloc с не weak linkage и прикомпоновать его к основному бинарнику.
> По-моему malloc и free определены (по крайней мере в GNU Libc) как weak.
Weak значит, что функция может быть переопределена, то есть взята при линковке из другого модуля?
> Даже не копаясь в потрохах Libc можно при каждом malloc(x) вызывать libc_malloc(x+sizeof(unsigned long)) и хранить размер выделенной памяти в конце блока,
В конце выделенного блока? А как конец блока узнать-то? По условию у нас только указатель. Или имелся в виду какой-то другой блок?
> определить свой malloc с не weak linkage и прикомпоновать его к основному бинарнику.
Решение с mymalloc мне кажется более переносимым и понятным. Заменить же вызовы malloc на mymalloc, free на myfree и т.д. в программе особого труда не должно составить.
>Weak значит, что функция может быть переопределена, то есть взята при линковке из другого модуля?
>В конце выделенного блока? А как конец блока узнать-то? По условию у нас только указатель. Или имелся в виду какой-то другой блок?
Извиняюсь, стормозил. В начале, конечно же. Аналогично переопределить free.
>Решение с mymalloc мне кажется более переносимым и понятным. Заменить же вызовы malloc на mymalloc, free на myfree и т.д. в программе особого труда не должно составить.
При наличии исходного текста, где память выделяется только через malloc (но не через new в плюсовом коде, например) определение своей функции - действительно более простой способ.
Предложенный мной способ хорош тем, что должен работать и при наличии объектников от приложения(исходный код необязателен).
> В начале, конечно же. Аналогично переопределить free.
Еще надо возврашать указатель не на начало выделенного блока, а с учетом смещения на размер поля, хранящего длину. Собственно реализацию всего этого и можно подсмотреть в исходниках postfix'а.
Читайте также: