Почему печать приводит к такому значительному увеличению разрыва кучи?

Я написал следующую программу,

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include "rand.h"

int main (int argc, char* argv[]) {

  void *x = sbrk(0);
  printf("The initial top of the heap is %p.\n", x);
  void *y = sbrk(0);
  printf("The current top of the heap is %p.\n", y);
  printf("The difference is %d (%x)\n", (int) (y-x), (int) (y-x));
  return 0;
}

Я понимаю, почему разрыв кучи отличается: он должен выделять пространство в куче для вызовов печати.

Чего я не понимаю, так это почему на моем компьютере с Linux x86_64 разница составляет именно 25600 байт.

Например, самой строке, вероятно, требуется лишь небольшое количество байтов (каждый байт — это символ, добавьте немного данных заголовка к строке в куче), а даже близко не требуется даже 1000 байт, верно?

У меня было небольшое предположение, что это может быть как-то связано с пейджингом, чего я пока не совсем понимаю. Но при беглом поиске кажется, что подкачка в любом случае выделяет только около 4000 байт за раз, так что, вероятно, это тоже не так, верно?

Может быть, различные include имеют к этому какое-то отношение? Я, честно говоря, не знаю, как это вообще влияет на память кучи.


В любом случае, прямой вопрос: почему эта программа заставляет кучную память перемещаться на 25600 байт?

Возможно, буферы stdout и другие структуры и данные не выделяются до первого вызова printf (или любой другой функции, использующей stdout). На самом деле для строки формата или самой сгенерированной строки не выделяется память, она напрямую использует частные буферы.

Some programmer dude 26.07.2024 20:57

Обратите внимание, что арифметика с указателями void * не определена стандартом C. Это сбивающее с толку расширение GCC: насколько велик ничтожный объект, у которого нет типа и который не существует?

Andrew Henle 26.07.2024 21:08

@AndrewHenle Возможно, я ошибаюсь, но я думал, что смысл void * заключался в том, чтобы просто изучить сам адрес, не смягчаемый интерпретацией системы типов. Я имею в виду, что можно таким образом сжечь сетчатку, но это для науки, так что...

Addem 26.07.2024 21:31

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

Addem 26.07.2024 21:39

Как сказал какой-то чувак-программист. Выполните еще один printf, а затем еще один sbrk(0). Я подозреваю, что это не сильно изменится, если вообще изменится.

Streve Ford 26.07.2024 21:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Почему печать приводит к такому значительному увеличению разрыва кучи?

Поскольку «печать» выделяет память, поэтому перемещается разрыв кучи. Запустив программу под отладчиком, вы можете заметить:

(gdb) bt
#0  __GI___sbrk (increment=increment@entry=135168) at sbrk.c:37
#1  0x00007ffff7e45b36 in __glibc_morecore (increment=increment@entry=135168) at /usr/src/debug/glibc/glibc/malloc/morecore.c:29
#2  0x00007ffff7e46bfd in sysmalloc (nb=nb@entry=656, av=av@entry=0x7ffff7f87ac0 <main_arena>) at malloc.c:2709
#3  0x00007ffff7e47c5a in _int_malloc (av=av@entry=0x7ffff7f87ac0 <main_arena>, bytes=bytes@entry=640) at malloc.c:4481
#4  0x00007ffff7e47f37 in tcache_init () at malloc.c:3252
#5  0x00007ffff7e48776 in tcache_init () at malloc.c:3248
#6  __GI___libc_malloc (bytes=bytes@entry=1024) at malloc.c:3313
#7  0x00007ffff7e21f14 in __GI__IO_file_doallocate (fp=0x7ffff7f885c0 <_IO_2_1_stdout_>) at filedoalloc.c:101
#8  0x00007ffff7e31214 in __GI__IO_doallocbuf (fp=0x7ffff7f885c0 <_IO_2_1_stdout_>) at /usr/src/debug/glibc/glibc/libio/libioP.h:1030
#9  __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7f885c0 <_IO_2_1_stdout_>) at genops.c:342
#10 0x00007ffff7e2f2e8 in _IO_new_file_overflow (f=0x7ffff7f885c0 <_IO_2_1_stdout_>, ch=-1) at fileops.c:745
#11 0x00007ffff7e2fde8 in _IO_new_file_xsputn (f=0x7ffff7f885c0 <_IO_2_1_stdout_>, data=<optimized out>, n=47)
    at /usr/src/debug/glibc/glibc/libio/libioP.h:1030
#12 _IO_new_file_xsputn (f=0x7ffff7f885c0 <_IO_2_1_stdout_>, data=<optimized out>, n=47) at fileops.c:1197
#13 0x00007ffff7dfd549 in __printf_buffer_flush_to_file (buf=buf@entry=0x7fffffffd9b0) at ../libio/libioP.h:1030
#14 0x00007ffff7dfd60c in __printf_buffer_to_file_done (buf=buf@entry=0x7fffffffd9b0) at printf_buffer_to_file.c:120
#15 0x00007ffff7e08e0c in __vfprintf_internal (s=0x7ffff7f885c0 <_IO_2_1_stdout_>, 
    format=0x555555556008 "The initial top of the heap is %p.\n", ap=ap@entry=0x7fffffffdab0, mode_flags=mode_flags@entry=0)
    at vfprintf-internal.c:1545
#16 0x00007ffff7dfccf3 in __printf (format=<optimized out>) at printf.c:33
#17 0x0000555555555181 in main ()

Выделение происходит из буфера выделения glibc для стандартного вывода в https://github.com/lattera/glibc/blob/master/libio/fileops.c#L752.

Другие вопросы по теме