Для программы из http://bellard.org/mersenne.html GCC создает исполняемый файл размером ~ 130 МБ. Почему?

6
mikhaelkh 13 Дек 2012 в 12:12
5
Думаю, этот массив t [1 << 25] занимает около 129 МБ памяти.
 – 
Mithrandir
13 Дек 2012 в 12:24

1 ответ

Лучший ответ

Попробуйте изменить t[1<<25]={2} на t[1<<25], и размер * исполняемого файла ** уменьшится до 7,3 КБ . (Излишне говорить, что вы не получите правильных результатов)

Если бы это было просто t[1<<25], оно бы вообще не заняло места.

Загвоздка здесь в том, что массив инициализируется (первый элемент = 2, следующие 2 ^ 25-1 элементов все 0), а глобальный массив помещается в сегмент данных только потому, что он инициализирован. .


Генерация сборки для двух версий и изучение различий делает ее еще более понятной:
[axiom@axiom ~]$ diff without_mem.s with_mem.s 
15c15,21
<   .comm   t,134217728,32
---
>   .globl  t
>   .align 32
>   .type   t, @object
>   .size   t, 134217728
> t:                                ***<- HERE!***
>   .long   2                
>   .zero   134217724

Как мы можем заметить, в исходной версии ассемблер направлен на создание 2 ^ 27 (134217728) байтов в сегменте данных. Таким образом, он становится частью самого объектного файла. ( Вы можете сгенерировать сборку путем компиляции с помощью переключателя -S gcc -S -fverbose-asm t1.c )


Но почему 129 МБ?
   1<< n= 2^n (1 left shifted n times). 
 =>  1<<25=2^25. 
     now 1 Integer= 4 bytes =2^2 bytes 
 => 2^25 Integers=2^27 bytes=2^7 * 1 M bytes= 128 MBs 
    

Для получения дополнительной информации см.:
*Примечание 1: это Объектный файл В строгих условиях.

Примечание 2: Как указано в комментариях, можно также отметить, что общий размер процесса (выполняемой программы) будет 129 МБ, даже если размер исполняемого файла составляет 7,3 КБ. (Память будет выделена после начала выполнения программы). Вы можете увидеть использование памяти вашей программой, используя команду top.

Примечание 3: стоит подчеркнуть, что это справедливо только потому, что t является глобальным. Распределение данных, локальных для функции, по-прежнему происходит во время выполнения в стеке. Таким образом, если бы t был локальным, объектный файл занял бы всего 7,3 КБ.

Примечание 4: Инициализированные локальные переменные static, как и инициализированные глобальные переменные, также хранятся в сегменте data. Глобальное значение static то же , что и глобальное, за исключением того, что вы ограничиваете область действия переменной только текущим файлом.

12
14 revs 23 Май 2017 в 14:55
Даже если размер исполняемого файла составляет 7,3 КБ, размер процесса все равно будет 130 МБ.
 – 
brian beuning
13 Дек 2012 в 19:31
Это довольно очевидно, но все же добавлено для полноты картины.
 – 
axiom
13 Дек 2012 в 20:22
Это потрясающе, я много раз инициализировал массивы значительного размера с помощью скобок с помощью GCC и никогда не видел ничего подобного. В исполняемый файл помещаются только неоднородные данные, все остальное инициализируется с помощью цикла, подобного memset. Может быть, используются какие-то странные флаги оптимизации или отладки?
 – 
Damon
14 Дек 2012 в 21:33
Да, конечно. Но оказывается, что сегмент данных действительно заполнен инициализированными глобальными данными. Я скомпилировал без каких-либо флагов оптимизации и отладки (символы отладки в любом случае занимают 1,4 Кбайт для этой программы). Для данных, локальных для функции, распределение происходит во время выполнения (в стеке), поэтому, если бы это был локальный массив, размер был бы всего 7,3 КБ. После загрузки процесс будет занимать 129 МБ, поэтому это становится проблемой только в том случае, если мы имеем дело с ситуацией, когда вторичная память меньше основной.
 – 
axiom
14 Дек 2012 в 22:02
1
@axiom: Это (в большинстве реализаций) поместит этот массив огромный в стек. Многие системы выделяют для стека меньше места, чем для статических данных.
 – 
Keith Thompson
15 Дек 2012 в 02:23