代码之家  ›  专栏  ›  技术社区  ›  Addem

为什么打印会导致堆破裂增加这么多?

  •  0
  • Addem  · 技术社区  · 2 年前

    我写了以下程序,

    #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;
    }
    

    我理解为什么堆中断是不同的,因为它必须为要打印的调用分配堆空间。

    我不明白的是,为什么在我的x86_64 Linux计算机上,差异具体为25600字节。

    比如,字符串本身可能只需要少量的字节(每个字节都是一个char,在堆中的字符串中添加一点头数据),根本不需要1000个字节,对吧?

    我有点猜测,这可能与分页有关——我还不太明白。但从简短的搜索来看,分页似乎一次只分配大约4000个字节,所以这可能也不是,对吧?

    也许各种 include 这跟你有关系吗?老实说,我根本不知道这对堆内存有什么影响。


    不管怎样,直接的问题是:为什么这个程序会导致堆内存移动25600字节?

    1 回复  |  直到 2 年前
        1
  •  1
  •   KamilCuk    2 年前

    为什么打印会导致堆破裂增加这么多?

    因为“打印”会分配内存,所以会移动堆断点。在调试器下运行程序时,您可能会观察到:

    (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为stdout分配缓冲区 https://github.com/lattera/glibc/blob/master/libio/fileops.c#L752 .