У меня есть следующая структура:

#define M 3

#pragma pack(push)
#pragma pack(1)
struct my_btree_node {
    struct my_btree_node *pointers[M];
    unsigned char *keys[M - 1];
    int data[M - 1];
    unsigned char number_of_keys;
};
#pragma pack(pop)

Функция sizeof(struct my_btree_node) возвращает значение 49 байт для этой структуры. Выделение памяти для этой структуры с помощью malloc возвращает 64-байтовый блок, потому что в 64-битных системах указатели выровнены по 16 байтам, или это действительно будет 49 байтов?

Есть ли способ выровнять память с меньшей степенью двойки, чем 16, и можно ли внутри приложения получить истинный размер выделенной памяти?

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

-2
aQuip 17 Мар 2015 в 12:19
Для какой архитектуры (IA) вы компилируете?
 – 
aggsol
17 Мар 2015 в 12:27
1
Зачем? Выравнивание это хорошо.
 – 
Matt
17 Мар 2015 в 12:29
Архитектура x86_64
 – 
aQuip
17 Мар 2015 в 12:32
Чтобы не использовать байты заполнения для экономии памяти
 – 
aQuip
17 Мар 2015 в 12:33
15 байт это не большой выигрыш. Но если у вас слишком много структур, то есть массив структур, вы можете просто разделить данные на несколько массивов, так как массивы никогда не дополняются.
 – 
Matt
17 Мар 2015 в 12:38

2 ответа

malloc(3) определен к

Функции malloc() и calloc() возвращают указатель на выделенный память, которая подходящим образом выровнена для любого встроенного типа. При ошибке, эти функции возвращают NULL. NULL также может возвращаться успешный вызов malloc() с нулевым size или успешным вызов calloc() с nmemb или size равным нулю.

Таким образом, соответствующая реализация должна возвращать указатель, выровненный по максимально возможному выравниванию машины (с GCC, это макрос __BIGGEST_ALIGNMENT__)

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

Кстати, malloc практически реализован в стандартной библиотеке C (но по крайней мере в Linux компилятор знает об этом благодаря __attribute__-s в заголовки GNU glibc; так что некоторые внутренние оптимизации внутри GCC знают и принимают заботиться о вызовах malloc).

2
Basile Starynkevitch 17 Мар 2015 в 12:57

malloc использует внутреннюю структуру кучи. Это зависит от реализации, но можно ожидать, что память будет выделена целым числом (внутренних) блоков. Поэтому обычно невозможно выделить ровно 49 байт одним вызовом malloc. Для этого вы можете построить какую-нибудь собственную подсистему поверх malloc, но я не вижу причин, по которым вам это может понадобиться.

P.S. Чтобы уменьшить расход памяти, вы можете предварительно выделить массив, состоящий, скажем, из 100 структур, когда вам нужна еще одна, и возвращать &a[i] до тех пор, пока все свободные индексы не будут потрачены впустую. Поскольку массивы никогда не дополняются, потери памяти уменьшатся примерно в 100 раз.

1
Matt 17 Мар 2015 в 12:48