`
mqzhuang
  • 浏览: 187296 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Glibc内存管理--ptmalloc2源代码分析(十四)

 
阅读更多

.2.2  Large bins

SIZE_SZ 4B 的平台上,大于等于 512B 的空闲 chunk ,或者,在 SIZE_SZ 8B 的平台上,大小大于等于 1024B 的空闲 chunk ,由 sorted bins 管理。 Large bins 一共包括 63 bin ,每个 bin 中的 chunk 大小不是一个固定公差的等差数列,而是分成 6 bin ,每组 bin 是一个固定公差的等差数列,每组的 bin 数量依次为 32 16 8 4 2 1 ,公差依次为 64B 512B 4096B 32768B 262144B 等。

SIZE_SZ 4B 的平台为例,第一个 large bin 的起始 chunk 大小为 512B ,共 32 bin ,公差为 64B ,等差数列满足如下关系:

Chunk_size=512 + 64 * index

第二个 large bin 的起始 chunk 大小为第一组 bin 的结束 chunk 大小,满足如下关系:

Chunk_size=512 + 64 * 32 + 512 * index

同理,我们可计算出每个 bin 的起始 chunk 大小和结束 chunk 大小。这些 bin 都是很有规律的,其实 small bins 也是满足类似规律, small bins 可以看着是公差为 8 的等差数列,一共有 64 bin (第 0 1bin 不存在),所以我们可以将 small bins large bins 存放在同一个包含 128 chunk 的数组上,数组的前一部分位 small bins ,后一部分为 large bins ,每个 bin index chunk 数组的下标,于是,我们可以根据数组下标计算出该 bin chunk 大小( small bins )或是 chunk 大小范围( large bins ),也可以根据需要分配内存块大小计算出所需 chunk 所属 bin index ptmalloc 使用了一组宏巧妙的实现了这种计算。

#define NBINS             128
#define NSMALLBINS         64
#define SMALLBIN_WIDTH    MALLOC_ALIGNMENT
#define MIN_LARGE_SIZE    (NSMALLBINS * SMALLBIN_WIDTH)

#define in_smallbin_range(sz)  \
  ((unsigned long)(sz) < (unsigned long)MIN_LARGE_SIZE)

#define smallbin_index(sz) \
  (SMALLBIN_WIDTH == 16 ? (((unsigned)(sz)) >> 4) : (((unsigned)(sz)) >> 3))

#define largebin_index_32(sz)                                                \
(((((unsigned long)(sz)) >>  6) <= 38)?  56 + (((unsigned long)(sz)) >>  6): \
 ((((unsigned long)(sz)) >>  9) <= 20)?  91 + (((unsigned long)(sz)) >>  9): \
 ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \
 ((((unsigned long)(sz)) >> 15) <=  4)? 119 + (((unsigned long)(sz)) >> 15): \
 ((((unsigned long)(sz)) >> 18) <=  2)? 124 + (((unsigned long)(sz)) >> 18): \
                                        126)

// XXX It remains to be seen whether it is good to keep the widths of
// XXX the buckets the same or whether it should be scaled by a factor
// XXX of two as well.
#define largebin_index_64(sz)                                                \
(((((unsigned long)(sz)) >>  6) <= 48)?  48 + (((unsigned long)(sz)) >>  6): \
 ((((unsigned long)(sz)) >>  9) <= 20)?  91 + (((unsigned long)(sz)) >>  9): \
 ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \
 ((((unsigned long)(sz)) >> 15) <=  4)? 119 + (((unsigned long)(sz)) >> 15): \
 ((((unsigned long)(sz)) >> 18) <=  2)? 124 + (((unsigned long)(sz)) >> 18): \
                                        126)

#define largebin_index(sz) \
  (SIZE_SZ == 8 ? largebin_index_64 (sz) : largebin_index_32 (sz))

#define bin_index(sz) \
 ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz))

      bin_index(sz) 根据所需内存大小计算出所需 bin index ,如果所需内存大小属于 small bins 的大小范围,调用 smallbin_index(sz) ,否则调用 largebin_index(sz)) smallbin_index(sz) 的计算相当简单,如果 SIZE_SZ 4B ,则将 sz 除以 8 ,如果 SIZE_SZ 8B ,则将 sz 除以 16 ,也就是除以 small bins 中等差数列的公差。 largebin_index(sz) 的计算相对复杂一些,可以用如下的表格直观的显示 chunk 的大小范围与 bin index 的关系。以 SIZE_SZ 4B 的平台为例, chunk 大小与 bin index 的对应关系如下表所示:(博客编辑器太弱,不能全部贴出来)

 

开始( 字节)

结束(字节)

Bin index

0

7

不存在

8

15

不存在

16

23

2

24

31

3

32

39

4

40

47

5

48

55

6

56

63

7

64

71

8

72

79

9

80

87

10

88

95

11

96

103

12

104

111

13

112

119

14

120

127

15

128

135

16

136

143

17

144

151

18

152

159

19

160

167

20

168

175

21

176

183

22

184

191

23

192

199

24

200

207

25

208

215

26

216

223

27

224

231

28

232

239

29

240

247

30

248

255

31

256

263

32

 

    注意:上表是 chunk 大小与 bin index 的对应关系,如果对于用户要分配的内存大小 size ,必须先使用 checked_request2size(req, sz) 计算出 chunk 的大小,再使用 bin_index(sz) 计算出 chunk 所属的 bin index

         对于 SIZE_SZ 4B 的平台, bin[0] bin[1] 是不存在的,因为最小的 chunk 16B small bins 一共 62 个, large bins 一共 63 个,加起来一共 125 bin 。而 NBINS 定义为 128 ,其实 bin[0] bin[127] 都不存在, bin[1] unsorted bin chunk 链表头。

typedef struct malloc_chunk* mbinptr;

/* addressing -- note that bin_at(0) does not exist */
#define bin_at(m, i) \
  (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2]))                           \
             - offsetof (struct malloc_chunk, fd))

/* analog of ++bin */
#define next_bin(b)  ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1)))

/* Reminders about list directionality within bins */
#define first(b)     ((b)->fd)
#define last(b)      ((b)->bk)

/* Take a chunk off a bin list */
#define unlink(P, BK, FD) {                                            \
  FD = P->fd;                                                          \
  BK = P->bk;                                                          \
  if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                \
    malloc_printerr (check_action, "corrupted double-linked list", P); \
  else {                                                               \
    FD->bk = BK;                                                       \
    BK->fd = FD;                                                       \
    if (!in_smallbin_range (P->size)                                   \
        && __builtin_expect (P->fd_nextsize != NULL, 0)) {             \
      assert (P->fd_nextsize->bk_nextsize == P);                       \
      assert (P->bk_nextsize->fd_nextsize == P);                       \
      if (FD->fd_nextsize == NULL) {                                   \
        if (P->fd_nextsize == P)                                       \
          FD->fd_nextsize = FD->bk_nextsize = FD;                      \
        else {                                                         \
          FD->fd_nextsize = P->fd_nextsize;                            \
          FD->bk_nextsize = P->bk_nextsize;                            \
          P->fd_nextsize->bk_nextsize = FD;                            \
          P->bk_nextsize->fd_nextsize = FD;                            \
        }                                                              \
      } else {                                                         \
        P->fd_nextsize->bk_nextsize = P->bk_nextsize;                  \
        P->bk_nextsize->fd_nextsize = P->fd_nextsize;                  \
      }                                                                \
    }                                                                  \
  }                                                                    \
}

    bin_at(m, i) 通过 bin index 获得 bin 的链表头, chunk 中的 fb bk 用于将空闲 chunk 链入链表中,而对于每个 bin 的链表头,只需要这两个域就可以了, prev_size size 对链表都来说都没有意义,浪费空间, ptmalloc 为了节约这点内存空间,增大 cpu 高速缓存的命中率,在 bins 数组中只为每个 bin 预留了两个指针的内存空间用于存放 bin 的链表头的 fb bk 指针。

         bin_at(m, i) 的定义可以看出, bin[0] 不存在,以 SIZE_SZ 4B 的平台为例, bin[1] 的前 4B 存储的是指针 fb ,后 4B 存储的是指针 bk ,而 bin_at 返回的是 malloc_chunk 的指针,由于 fb malloc_chunk 的偏移地址为 offsetof (struct malloc_chunk, fd))=8 ,所以用 fb 的地址减去 8 就得到 malloc_chunk 的地址。但切记,对 bin 的链表头的 chunk ,一定不能修改 prev_size size 域,这两个域是与其他 bin 的链表头的 fb bk 内存复用的。

     宏 next_bin(b) 用于获得下一个 bin 的地址,根据前面的分析,我们知道只需要将当前 bin 的地址向后移动两个指针的长度就得到下一个 bin 的链表头地址。

     每个 bin 使用双向循环链表管理空闲 chunk bin 的链表头的指针 fb 指向第一个可用的 chunk ,指针 bk 指向最后一个可用的 chunk 。宏 first(b) 用于获得 bin 的第一个可用 chunk ,宏 last(b) 用于获得 bin 的最后一个可用的 chunk ,这两个宏便于遍历 bin ,而跳过 bin 的链表头。

     宏 unlink(P, BK, FD) 用于将 chunk 从所在的空闲链表中取出来,注意 large bins 中的空闲 chunk 可能处于两个双向循环链表中, unlink 时需要从两个链表中都删除。

 

分享到:
评论

相关推荐

    Glibc内存管理--ptmalloc2源代码分析(三十四)

    《Glibc内存管理--ptmalloc2源代码分析》 Glibc是GNU项目提供的C语言标准库,它在Linux系统中扮演着至关重要的角色。其中,内存管理是Glibc中的核心部分,它负责程序运行时的内存分配与释放,对系统的性能有着深远...

    glibc内存管理ptmalloc源代码分析PDF

    在分析glibc内存管理的ptmalloc源代码之前,我们需要先了解一些基础知识,包括操作系统对内存的分配和管理方法,以及glibc内存分配机制。 内存管理是操作系统的一个核心功能,它负责维护和管理计算机系统中的物理和...

    glibc内存管理ptmalloc源代码分析-高清PDF-pdf版

    《glibc内存管理ptmalloc源代码分析》是一份深入探讨Linux系统中glibc库内存管理机制的专业资料。glibc,全称GNU C Library,是Linux操作系统下广泛使用的C语言标准库,其中ptmalloc是glibc中负责动态内存分配的核心...

    glibc内存管理ptmalloc源代码分析@华庭1

    在深入探讨Glibc内存管理的Ptmalloc源代码之前,我们先来了解一下内存管理的基本概念。内存管理是操作系统和编程语言库中的核心组件,它负责有效地分配和回收内存,以确保程序的高效运行和资源的有效利用。 2.1 X86...

    glibc内存管理ptmalloc源代码分析4.pdf

    通过对ptmalloc源代码的深入分析,可以找到潜在的优化点,如调整分配策略、改进数据结构设计等,以解决这些问题。 #### 13. 使用注意事项 虽然ptmalloc提供了强大的内存管理功能,但在使用过程中也需要注意一些事项...

    glibc内存管理ptmalloc源代码分析.pdf

    glibc内存管理ptmalloc源代码分析

    glibc内存管理ptmalloc源代码分析1

    在深入探讨Glibc内存管理的Ptmalloc源代码之前,我们先来了解一下内存管理的基本概念和Glibc中的Ptmalloc2。内存管理是操作系统和应用程序中的核心部分,它负责为程序分配和释放内存,以确保资源的有效利用和避免...

    glibc内存管理ptmalloc源代码分析

    ### glibc内存管理ptmalloc源代码分析 #### 1. 问题 在开发一款NoSQL系统的过程中,我们遇到一个令人头疼的问题:系统中使用的内存管理模块,在高并发、高负载的场景下,虽然已将内存释放给C运行时库(即glibc),...

    glibc内存管理ptmalloc源代码分析-清晰版.pdf

    ### glibc内存管理ptmalloc源代码分析-清晰版 #### 一、背景介绍与文档概览 本文档针对glibc中的ptmalloc2内存管理模块进行了深入的源代码分析,旨在帮助开发者更好地理解ptmalloc的工作原理及其内部机制。文档...

    Python-用于检测glibc堆ptmalloc的gdbpython库

    `glibc`是GNU项目提供的C标准库,而`ptmalloc`是它的一部分,负责程序的内存分配与管理。`ptmalloc`优化了内存分配效率,但在某些情况下也可能成为安全漏洞的来源。 `GDB`(GNU调试器)是一款强大的调试工具,它...

    内存管理与调试详细剖析

    本文将深入探讨内存管理的基本原理及其调试方法,特别关注于Linux环境下的Glibc内存管理库以及Ptmalloc2的具体实现。 #### 二、基础知识 ##### 2.1 X86平台Linux进程内存布局 **2.1.1 32位模式下进程内存经典布局...

    malloc源码分析glibc库

    通过对glibc库中的ptmalloc源代码进行深入分析,我们不仅了解了其内部实现机制,还能够针对实际应用中的内存管理问题提出有效的解决方案。这对于提升程序性能、减少内存碎片以及提高系统的整体稳定性具有重要意义。...

    pwn学习总结(八)—— 堆(持续更新)

    学习自《glibc内存管理ptmalloc源代码分析》庄明强 著 部分资料参考自互联网 chunk 描述: 当用户通过malloc等函数申请空间时,实际上是从堆中分配内存 目前 Linux 标准发行版中使用的是 glibc 中的堆分配器:...

    堆漏洞的利用技巧1

    《堆漏洞的利用技巧》 堆溢出是计算机安全领域中的一个重要...同时,阅读glibc内存管理的源代码分析对于提高理解和实践能力非常有帮助。通过这些知识的学习,不仅可以增强安全意识,也能提升在CTF竞赛中的攻防能力。

Global site tag (gtag.js) - Google Analytics