0%

Glibc源码阅读--宏定义

5fb790ef99865.jpg

chunk结构

1
2
3
4
5
6
7
8
9
10
11
12
struct malloc_chunk {

INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */

struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;

/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};

宏定义

1
#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))

这里结果为拿到mem地址

1
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))

这里结果为拿到该chunk的地址

1
#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))

返回最小的chunk,这里求了chunk结构体开头到fd_nextsize的偏移

1
2
3
4
/* The smallest size we can malloc is an aligned minimal chunk */

#define MINSIZE \
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))

这个式子的含义是求 MIN_CHUNK_SIZE 在 MALLOC_ALIGN_MASK + 1 的最小上界,MALLOC_ALIGN + 1 等于 MALLOC_ALIGNMENT ,所以这个式子的意思便是求满足字节对齐最小的可 malloc 分配的 chunk 。

1
2
3
4
5
6
7
/* Check if m has acceptable alignment */

#define aligned_OK(m) (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0)

#define misaligned_chunk(p) \
((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) \[]
& MALLOC_ALIGN_MASK)
  • intptr_t:其长度总是所在平台的位数,用来存放地址。
  • uintptr_t 是intptr_t 的无符号版本。
  • aligned_OK(m):m判断是否对齐
  • misaligned_chunk(p):实现p的对齐
1
2
3
#define REQUEST_OUT_OF_RANGE(req)                                 \
((unsigned long) (req) >= \
(unsigned long) (INTERNAL_SIZE_T) (-2 * MINSIZE))

REQUEST_OUT_OF_RANGE(req):如果申请大小加上两个最小块大小大于等于 unsigned long 的长度则置 1,否则置 0。

1
2
3
4
5
6
/* pad request bytes into a usable size -- internal version */

#define request2size(req) \
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \
MINSIZE : \
((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

将用户请求的大小转换成实际分配的大小,SIZE_SZ是下一个chunk的prev_size域的空间复用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Same, except also perform an argument and result check.  First, we check
that the padding done by request2size didn't result in an integer
overflow. Then we check (using REQUEST_OUT_OF_RANGE) that the resulting
size isn't so large that a later alignment would lead to another integer
overflow. */
#define checked_request2size(req, sz) \
({ \
(sz) = request2size (req); \
if (((sz) < (req)) \
|| REQUEST_OUT_OF_RANGE (sz)) \
{ \
__set_errno (ENOMEM); \
return 0; \
} \
})

判断申请大小是否溢出,没有溢出的情况下sz记录实际分配的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
#define PREV_INUSE 0x1

/* extract inuse bit of previous chunk */
#define prev_inuse(p) ((p)->mchunk_size & PREV_INUSE)


/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
#define IS_MMAPPED 0x2

/* check for mmap()'ed chunk */
#define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED)


/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
from a non-main arena. This is only set immediately before handing
the chunk to the user, if necessary. */
#define NON_MAIN_ARENA 0x4

/* Check for chunk from main arena. */
#define chunk_main_arena(p) (((p)->mchunk_size & NON_MAIN_ARENA) == 0)

/* Mark a chunk as not being on the main arena. */
#define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)
  • prev_inuse(p):为 0 则表示前一个 chunk 为空闲,为 1 表示前一个 chunk 正在使用。
  • chunk_is_mmapped(p):为 1 表示该 chunk 是从 mmap 映射区域分配的,否则是从 heap 区域分配的。
  • chunk_non_main_arena(p):为 1 表示该 chunk 属于非分配区,为 0 表示该 chunk 属于主分配区。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
Bits to mask off when extracting size

Note: IS_MMAPPED is intentionally not masked off from size field in
macros for which mmapped chunks should never be seen. This should
cause helpful core dumps to occur if it is tried by accident by
people extending or adapting this malloc.
*/
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)

/* Get size, ignoring use bits */
#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))

/* Like chunksize, but do not mask SIZE_BITS. */
#define chunksize_nomask(p) ((p)->mchunk_size)

/* Ptr to next physical malloc_chunk. */
#define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))

/* Size of the chunk below P. Only valid if prev_inuse (P). */
#define prev_size(p) ((p)->mchunk_prev_size)

/* Set the size of the chunk below P. Only valid if prev_inuse (P). */
#define set_prev_size(p, sz) ((p)->mchunk_prev_size = (sz))

/* Ptr to previous physical malloc_chunk. Only valid if prev_inuse (P). */
#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - prev_size (p))

/* Treat space at ptr + offset as a chunk */
#define chunk_at_offset(p, s) ((mchunkptr) (((char *) (p)) + (s)))
  • mchunkptr:指向malloc_chunk结构体
  • chunksize(p):获取size域低3位的值。
  • chunksize_nomask (p):当前chunk的size
  • next_chunk(p):获取下一个chunk的地址。
  • prev_size(p):获取当前chunk的prev_size
  • set_prev_size(p, sz):将当前chunk的prev_size赋值为前一个chunk的size
  • prev_chunk(p):获取上一个chunk的地址。
  • chunk_at_offset(p, s):将 p + s 的地址强制看作一个chunk。
1
2
3
4
5
6
7
8
9
/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)

#define set_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)

#define clear_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
  • inuse(p):获取当前 chunk 是否使用的标志位,为 1 正在使用,为 0 chunk 空闲。
  • set_inuse(p):将当前 chunk 的是否使用标志位置 1。
  • clear_inuse(p):将当前 chunk 的是否使用标志位置 0
1
2
3
4
5
6
7
8
9
/* check/set/clear inuse bits in known places */
#define inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size & PREV_INUSE)

#define set_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size |= PREV_INUSE)

#define clear_inuse_bit_at_offset(p, s) \
(((mchunkptr) (((char *) (p)) + (s)))->mchunk_size &= ~(PREV_INUSE))
  • inuse_bit_at_offset(p, s):获取指定 chunk 的 size 域的使用标志位
  • set_inuse_bit_at_offset(p, s):将指定 chunk 的 size 域的使用标志位置 1。
  • clear_inuse_bit_at_offset(p, s):将指定 chunk 的 size 域的使用标志位置 0。
1
2
3
4
5
6
7
8
/* Set size at head, without disturbing its use bit */
#define set_head_size(p, s) ((p)->mchunk_size = (((p)->mchunk_size & SIZE_BITS) | (s)))

/* Set size/use field */
#define set_head(p, s) ((p)->mchunk_size = (s))

/* Set size at footer (only when chunk is not in use) */
#define set_foot(p, s) (((mchunkptr) ((char *) (p) + (s)))->mchunk_prev_size = (s))
  • set_head_size(p, s)用于设置当前 chunk p 的 size 域并保留 size 域的控制信息。
  • set_head(p, s) 用于设置当前 chunk p 的 size 域并忽略已有的 size 域控制信息。
  • set_foot(p,s)用于设置当前chunk p的下一个chunk的prev_size为s,s为当前chunk的size,只有当chunkp 为空闲时才能使用这个宏,当前 chunk 的 foot 的内存空间存在于下一个 chunk,即下一个chunk 的 prev_size。

参考链接

https://www.cnblogs.com/luoleqi/p/11973523.html

glibc内存管理ptmalloc源代码分析