glibc源码分析(三)文件系统系统调用

最新博客地址 shankusu.me 

以下内容转载自

https://zhuanlan.zhihu.com/p/31496984
 

前文详细介绍了glibc封装系统调用的方法,在本文中我将向大家讲解glibc系统调用封装的具体的例子。这些例子都是关于文件系统的。

1.1 文件的创建与删除

linux支持7种文件:普通文件,目录文件,字符设备文件,块设备文件,管道文件,套接字文件,符号链接文件。每种文件的创建与删除都有对应系统调用。glibc封装了这些系统调用。

创建与删除文件的系统调用有:creat,unlink,mkdir,rmdir,mknod,symlink,link。与创建与删除文件的系统调用有关的系统调用有:umask。

其中unlink,mkdir,rmdir,symlink,link,umask是用脚本生成的。

unlink系统调用的封装代码

#define SYSCALL_NAME unlink
#define SYSCALL_NARGS 1
#define SYSCALL_SYMBOL __unlink
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__unlink, unlink)
hidden_weak (unlink)

mkdir系统调用的封装代码

#define SYSCALL_NAME mkdir
#define SYSCALL_NARGS 2
#define SYSCALL_SYMBOL __mkdir
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__mkdir, mkdir)
hidden_weak (mkdir)

rmdir系统调用的封装代码

#define SYSCALL_NAME rmdir
#define SYSCALL_NARGS 1
#define SYSCALL_SYMBOL __rmdir
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__rmdir, rmdir)
hidden_weak (rmdir)

symlink系统调用的封装代码

#define SYSCALL_NAME symlink
#define SYSCALL_NARGS 2
#define SYSCALL_SYMBOL __symlink
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__symlink, symlink)
hidden_weak (symlink)

link系统调用的封装代码

#define SYSCALL_NAME link
#define SYSCALL_NARGS 2
#define SYSCALL_SYMBOL __link
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__link, link)
hidden_weak (link)

umask系统调用的封装代码

#define SYSCALL_NAME umask
#define SYSCALL_NARGS 1
#define SYSCALL_SYMBOL __umask
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 1
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__umask, umask)
hidden_weak (umask)

mknod系统调用是.c文件封装的。它的源码如下:

int
attribute_hidden
__mknod (const char *path, mode_t mode, dev_t dev)
{
  return __xmknod (_MKNOD_VER, path, mode, &dev);
}

weak_hidden_alias (__mknod, mknod)

int
__xmknod (int vers, const char *path, mode_t mode, dev_t *dev)
{
  unsigned long long int k_dev;

  if (vers != _MKNOD_VER)
    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);

  /* We must convert the value to dev_t type used by the kernel.  */
  k_dev =  (*dev) & ((1ULL << 32) - 1);
  if (k_dev != *dev)
    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);

  return INLINE_SYSCALL (mknod, 3, path, mode, (unsigned int) k_dev);
}

weak_alias (__xmknod, _xmknod)
libc_hidden_def (__xmknod)

__mknod函数调用了__xmknod函数,__xmknod函数中使用INLINE_SYSCALL宏完成mknod系统调用的调用。

creat系统调用是.c文件封装的。它的源码如下:

int
__creat (const char *file, mode_t mode)
{
  return SYSCALL_CANCEL (creat, file, mode);
}
weak_alias (__creat, creat)

SYSCALL_CANCEL 宏调用了creat系统调用。SYSCALL_CANCEL宏做了单线程与多线程下调用系统调用的处理。

#define SYSCALL_CANCEL(...) \
  ({									     \
    long int sc_ret;							     \
    if (SINGLE_THREAD_P) 						     \
      sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); 			     \
    else								     \
      {									     \
	int sc_cancel_oldtype = LIBC_CANCEL_ASYNC ();			     \
	sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__);			     \
        LIBC_CANCEL_RESET (sc_cancel_oldtype);				     \
      }									     \
    sc_ret;								     \
  })

SYSCALL_CANCEL宏调用INLINE_SYSCALL_CALL宏完成系统调用的封装。

INLINE_SYSCALL_CALL宏

#define INLINE_SYSCALL_CALL(...) \
  __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__)

#define __INLINE_SYSCALL_DISP(b,...) \
  __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)

#define __SYSCALL_CONCAT_X(a,b)     a##b         //连接两个宏
#define __SYSCALL_CONCAT(a,b)       __SYSCALL_CONCAT_X (a, b)

#define __INLINE_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n    
#define __INLINE_SYSCALL_NARGS(...) \            //返回系统调用参数个数
  __INLINE_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,)

#define __INLINE_SYSCALL0(name) \
  INLINE_SYSCALL (name, 0)
#define __INLINE_SYSCALL1(name, a1) \
  INLINE_SYSCALL (name, 1, a1)
#define __INLINE_SYSCALL2(name, a1, a2) \
  INLINE_SYSCALL (name, 2, a1, a2)
#define __INLINE_SYSCALL3(name, a1, a2, a3) \
  INLINE_SYSCALL (name, 3, a1, a2, a3)
#define __INLINE_SYSCALL4(name, a1, a2, a3, a4) \
  INLINE_SYSCALL (name, 4, a1, a2, a3, a4)
#define __INLINE_SYSCALL5(name, a1, a2, a3, a4, a5) \
  INLINE_SYSCALL (name, 5, a1, a2, a3, a4, a5)
#define __INLINE_SYSCALL6(name, a1, a2, a3, a4, a5, a6) \
  INLINE_SYSCALL (name, 6, a1, a2, a3, a4, a5, a6)
#define __INLINE_SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \
  INLINE_SYSCALL (name, 7, a1, a2, a3, a4, a5, a6, a7)

最终,调用INLINE_SYSCALL 宏完成系统调用封装。

1.2 文件属性的获取与修改

linux中每种文件都有其属性,属性可以获取与修改。unix提供了系统调用用于属性的获取与修改。

1.2.1 文件属性获取

linux中关于文件属性获取的系统调用有9个:oldstat(18),oldfstat(28),oldlstat(84),stat(106),lstat(107),fstat(108),stat64(195),lstat64(196),fstat64(197)。glibc封装了6个系统调用,它们分别是:stat,lstat,fstat,stat64,lstat64,fstat64。这6个系统调用都是使用.c文件封装的。

stat函数的源码如下:

#undef stat
int
attribute_hidden
__stat (const char *file, struct stat *buf)
{
  return __xstat (_STAT_VER, file, buf);
}

weak_hidden_alias (__stat, stat)

int
__xstat (int vers, const char *name, struct stat *buf)
{
  int result;

  if (vers == _STAT_VER_KERNEL)
    return INLINE_SYSCALL (stat, 2, name, buf);

  {
    struct stat64 buf64;

    INTERNAL_SYSCALL_DECL (err);
    result = INTERNAL_SYSCALL (stat64, err, 2, name, &buf64);
    if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
                                    err));
    else
      return __xstat32_conv (vers, &buf64, buf);
  }
}
hidden_def (__xstat)
weak_alias (__xstat, _xstat);

__stat函数调用了__xstat函数。__xstat函数使用INTERNAL_SYSCALL宏调用了stat64系统调用。如果调用成功则转化stat64结构数据为stat结构数据。

__xstat32_conv函数源码如下:

int
__xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf)
{
  switch (vers)
    {
    case _STAT_VER_LINUX:
      {

    buf->st_dev = kbuf->st_dev;
#ifdef _HAVE_STAT___PAD1
    buf->__pad1 = 0;
#endif
#ifdef _HAVE_STAT64___ST_INO
# if !__ASSUME_ST_INO_64_BIT
    if (kbuf->st_ino == 0)
      buf->st_ino = kbuf->__st_ino;
    else
# endif
      {
        buf->st_ino = kbuf->st_ino;
        if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
        && buf->st_ino != kbuf->st_ino)
          return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
      }
#else
    buf->st_ino = kbuf->st_ino;
    if (sizeof (buf->st_ino) != sizeof (kbuf->st_ino)
        && buf->st_ino != kbuf->st_ino)
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
#endif
    buf->st_mode = kbuf->st_mode;
    buf->st_nlink = kbuf->st_nlink;
    buf->st_uid = kbuf->st_uid;
    buf->st_gid = kbuf->st_gid;
    buf->st_rdev = kbuf->st_rdev;
#ifdef _HAVE_STAT___PAD2
    buf->__pad2 = 0;
#endif
    buf->st_size = kbuf->st_size;
    /* Check for overflow.  */
    if (sizeof (buf->st_size) != sizeof (kbuf->st_size)
        && buf->st_size != kbuf->st_size)
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
    buf->st_blksize = kbuf->st_blksize;
    buf->st_blocks = kbuf->st_blocks;
    /* Check for overflow.  */
    if (sizeof (buf->st_blocks) != sizeof (kbuf->st_blocks)
        && buf->st_blocks != kbuf->st_blocks)
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EOVERFLOW);
#ifdef _HAVE_STAT_NSEC
    buf->st_atim.tv_sec = kbuf->st_atim.tv_sec;
    buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec;
    buf->st_mtim.tv_sec = kbuf->st_mtim.tv_sec;
    buf->st_mtim.tv_nsec = kbuf->st_mtim.tv_nsec;
    buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec;
    buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec;
#else
    buf->st_atime = kbuf->st_atime;
    buf->st_mtime = kbuf->st_mtime;
    buf->st_ctime = kbuf->st_ctime;
#endif

#ifdef _HAVE_STAT___UNUSED1
    buf->__glibc_reserved1 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED2
    buf->__glibc_reserved2 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED3
    buf->__glibc_reserved3 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED4
    buf->__glibc_reserved4 = 0;
#endif
#ifdef _HAVE_STAT___UNUSED5
    buf->__glibc_reserved5 = 0;
#endif
      }
      break;

      /* If struct stat64 is different from struct stat then
     _STAT_VER_KERNEL does not make sense.  */
    case _STAT_VER_KERNEL:
    default:
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
    }

  return 0;
}

#define _STAT_VER_LINUX     3
#define _STAT_VER       _STAT_VER_LINUX

lstat函数源码如下:

#undef lstat
#undef __lstat
int
attribute_hidden
__lstat (const char *file, struct stat *buf)
{
  return __lxstat (_STAT_VER, file, buf);
}

weak_hidden_alias (__lstat, lstat)

int
__lxstat (int vers, const char *name, struct stat *buf)
{
  int result;

  if (vers == _STAT_VER_KERNEL)
    return INLINE_SYSCALL (lstat, 2, name, buf);

  {
    struct stat64 buf64;

    INTERNAL_SYSCALL_DECL (err);
    result = INTERNAL_SYSCALL (lstat64, err, 2, name, &buf64);
    if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
                                    err));
    else
      return __xstat32_conv (vers, &buf64, buf);
  }
}

hidden_def (__lxstat)
weak_alias (__lxstat, _lxstat);

__lstat函数调用了__lxstat函数。__lxstat函数使用INTERNAL_SYSCALL宏调用了lstat64系统调用。如果调用成功则转化stat64结构数据为stat结构数据。

fstat函数源码如下:

#undef fstat
#undef __fstat
int
attribute_hidden
__fstat (int fd, struct stat *buf)
{
  return __fxstat (_STAT_VER, fd, buf);
}

weak_hidden_alias (__fstat, fstat)

int
__fxstat (int vers, int fd, struct stat *buf)
{
  int result;

  if (vers == _STAT_VER_KERNEL)
    return INLINE_SYSCALL (fstat, 2, fd, buf);

  {
    struct stat64 buf64;

    INTERNAL_SYSCALL_DECL (err);
    result = INTERNAL_SYSCALL (fstat64, err, 2, fd, &buf64);
    if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
      return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
                                    err));
    else
      return __xstat32_conv (vers, &buf64, buf);
  }
}

hidden_def (__fxstat)
weak_alias (__fxstat, _fxstat);

__fstat函数调用了__fxstat函数。__fxstat函数使用INTERNAL_SYSCALL宏调用了fstat64系统调用。如果调用成功则转化stat64结构数据为stat结构数据。

stat64函数源码如下:

#undef stat64
int
attribute_hidden
stat64 (const char *file, struct stat64 *buf)
{
  return __xstat64 (_STAT_VER, file, buf);
}

int
___xstat64 (int vers, const char *name, struct stat64 *buf)
{
  int result;
  result = INLINE_SYSCALL (stat64, 2, name, buf);
  return result;
}

stat64函数调用了__xstat64函数。__xstat64函数使用INLINE_SYSCALL宏调用了stat64系统调用。

lstat64函数源码如下:

#undef lstat64
int
attribute_hidden
lstat64 (const char *file, struct stat64 *buf)
{
  return __lxstat64 (_STAT_VER, file, buf);
}

int
___lxstat64 (int vers, const char *name, struct stat64 *buf)
{
  int result;
  result = INLINE_SYSCALL (lstat64, 2, name, buf);
  return result;
}

lstat64函数调用了__lxstat64函数。__lxstat64函数使用INLINE_SYSCALL宏调用了lstat64系统调用。

fstat函数源码如下:

#undef fstat64
int
attribute_hidden
fstat64 (int fd, struct stat64 *buf)
{
  return __fxstat64 (_STAT_VER, fd, buf);
}

int
___fxstat64 (int vers, int fd, struct stat64 *buf)
{
  int result;
  result = INLINE_SYSCALL (fstat64, 2, fd, buf);
  return result;
}

fstat64函数调用了__fxstat64函数。__fxstat64函数使用INLINE_SYSCALL宏调用了fstat64系统调用。

1.2.2 测试文件权限

linux中access系统调用用于测试文件权限。glibc封装了该系统调用。

access函数源码:

int
__access (const char *file, int type)
{
  return INLINE_SYSCALL_CALL (access, file, type);
}
weak_alias (__access, access)

1.2.3 修改文件权限

linux中关于修改文件权限的系统调用有2个,它们分别是:chmod(15),fchmod(94)。glibc封装了这两个系统调用。它们都是使用脚本封装的。

chmod系统调用的封装代码:

#define SYSCALL_NAME chmod
#define SYSCALL_NARGS 2
#define SYSCALL_SYMBOL __chmod
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__chmod, chmod)
hidden_weak (chmod)

fchmod系统调用的封装代码:

#define SYSCALL_NAME fchmod
#define SYSCALL_NARGS 2
#define SYSCALL_SYMBOL __fchmod
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__fchmod, fchmod)
hidden_weak (fchmod)

1.2.4 修改文件用户ID及组用户ID

linux中关于chown的系统调用有6个,它们分别是lchown(16),fchown(95),chown(182),lchown32(198),fchown32(207),chown32(212)。它们都是用于改变文件的用户ID和组用户ID。chown系列系统调用只能将用户ID和组用户ID改为16位整数。chown32系列系统调用则能将用户ID和组用户ID改为32位整数。

glibc封装了3个系统调用,分别封装为chown函数,fchown函数,lchown函数。它们都是通过脚本封装的。

chown函数的封装代码:

#define SYSCALL_NAME chown32
#define SYSCALL_NARGS 3
#define SYSCALL_SYMBOL __chown
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
#include <shlib-compat.h>
#if IS_IN (libc)
versioned_symbol (libc, __chown, chown, GLIBC_2_1)
#else
strong_alias (__chown, chown)
#endif

chown函数封装的是chown32系统调用。

fchown函数的封装代码:

#define SYSCALL_NAME fchown32
#define SYSCALL_NARGS 3
#define SYSCALL_SYMBOL __fchown
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
weak_alias (__fchown, fchown)
hidden_weak (fchown)

fchown函数封装的是fchown32系统调用。

lchown函数的封装代码:

#define SYSCALL_NAME lchown32
#define SYSCALL_NARGS 3
#define SYSCALL_SYMBOL __lchown
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>
#include <shlib-compat.h>
#if IS_IN (libc)
versioned_symbol (libc, __lchown, lchown, GLIBC_2_0)
#else
strong_alias (__lchown, lchown)
#endif
#if defined SHARED && IS_IN (libc)
strong_alias (__lchown, __lchown_1)
compat_symbol (libc, __lchown_1, chown, GLIBC_2_0)
#endif

lchown函数封装的是lchown32系统调用。

1.2.5 修改文件时间

linux中关于修改文件时间的系统调用有2个:utime(30),utimes(271)。glibc封装了这2个系统调用。utime系统调用是用脚本封装的,utimes系统调用是用.c文件封装的。

utime系统调用封装代码:

#define SYSCALL_NAME utime
#define SYSCALL_NARGS 2
#define SYSCALL_SYMBOL utime
#define SYSCALL_CANCELLABLE 0
#define SYSCALL_NOERRNO 0
#define SYSCALL_ERRVAL 0
#include <syscall-template.S>

utimes函数源码:

int
__utimes (const char *file, const struct timeval tvp[2])
{
  /* Avoid implicit array coercion in syscall macros.  */
  return INLINE_SYSCALL (utimes, 2, file, &tvp[0]);
}

weak_alias (__utimes, utimes)

1.2.6 截断文件

linux中截断文件的系统调用有4个:truncate(92),ftruncate(93),truncate64(193),ftruncate64(194)。glibc封装了这4个系统调用。

truncate函数的源码:

int
__truncate (const char *path, off_t length)
{
  return INLINE_SYSCALL_CALL (truncate, path, length);
}
weak_alias (__truncate, truncate)

ftruncate函数的源码:

int
__ftruncate (int fd, off_t length)
{
  return INLINE_SYSCALL_CALL (ftruncate, fd, length);
}
weak_alias (__ftruncate, ftruncate)

truncate64函数的源码:

int
__truncate64 (const char *path, off64_t length)
{
  return INLINE_SYSCALL_CALL (truncate64, path,
                  __ALIGNMENT_ARG SYSCALL_LL64 (length));
}
weak_alias (__truncate64, truncate64)

#ifdef __OFF_T_MATCHES_OFF64_T
weak_alias (__truncate64, truncate);
#endif

#define SYSCALL_LL64(val) \
  __LONG_LONG_PAIR ((long) ((val) >> 32), (long) ((val) & 0xffffffff))

#if __BYTE_ORDER == __LITTLE_ENDIAN
# define __LONG_LONG_PAIR(HI, LO) LO, HI
#elif __BYTE_ORDER == __BIG_ENDIAN
# define __LONG_LONG_PAIR(HI, LO) HI, LO
#endif

参数length是64位数据,需要转换为两个32位数据传给系统调用。源码中SYSCALL_LL64宏完成了这个处理。SYSCALL_LL64将64位数据转为两个32位数据,并根据是小端还是大端决定传入的顺序。

ftruncate64函数源码:

int
__ftruncate64 (int fd, off64_t length)
{
  return INLINE_SYSCALL_CALL (ftruncate64, fd,
                  __ALIGNMENT_ARG SYSCALL_LL64 (length));
}
weak_alias (__ftruncate64, ftruncate64)

1.2.7 修改文件标志位

在一些系统上(mac os)文件属性中还有一项---标志位字段。标志位可以标识文件是否隐藏,文件是否只添加等。不过,在linux中没有这一项,所以相关的系统调用只返回错误值。

chflags

int
chflags (const char *file, unsigned long int flags)
{
  if (file == NULL)
    {
      __set_errno (EINVAL);
      return -1;
    }

  __set_errno (ENOSYS);
  return -1;
}

fchflags

int
fchflags (int fd, unsigned long int flags)
{
  if (fd < 0)
    {
      __set_errno (EINVAL);
      return -1;
    }

  __set_errno (ENOSYS);
  return -1;
}
本文通过Glibc的内存暴增问题,主要介绍了系统的内存管理问题,具体如下: 目录 1. 问题 2. 基础知识 2.1 X86平台Linux进程内存布局 2.1.1 32位模式下进程内存经典布局 2.1.2 32位模式下进程默认内存布局 2.1.3 64位模式下进程内存布局 2.2 操作系统内存分配的相关函数 2.2.1 Heap操作相关函数 2.2.2 Mmap映射区域操作相关函数 3. 概述 3.1 内存管理一般性描述 3.1.1 内存管理的方法 3.1.2 内存管理器的设计目标 3.1.3 常见C内存管理程序 3.2 Ptmalloc内存管理概述 3.2.1 简介 3.2.2 内存管理的设计假设 3.2.3 内存管理数据结构概述 3.2.4 内存分配概述 3.2.5 内存回收概述 3.2.6 配置选项概述 3.2.7 使用注意事项 4. 问题分析及解决 5. 源代码分析 5.1 边界标记法 5.2 分箱式内存管理 5.2.1 Small bins 5.2.2 Large bins 5.2.3 Unsorted bin 5.2.4 Fast bins 5.3 核心结构体分析 5.3.1 malloc_state 5.3.2 Malloc_par 5.3.3 分配区的初始化 5.4 配置选项 5.5 Ptmalloc的初始化 5.5.1 Ptmalloc未初始化时分配/释放内存 5.5.2 ptmalloc_init()函数 5.5.3 ptmalloc_lock_all(),ptmalloc_unlock_all(),ptmalloc_unlock_all2() 5.6 多分配区支持 5.6.1 Heap_info 5.6.2 获取分配区 5.6.3 Arena_get2() 5.6.4 _int_new_arena() 5.6.5 New_heap() 5.6.6 get_free_list()和reused_arena() 5.6.7 grow_heap(),shrink_heap(),delete_heap(),heap_trim() 5.7 内存分配malloc 5.7.1 public_mALLOc() 5.7.2 _int_malloc() 5.8 内存释放free 5.8.1 Public_fREe() 5.8.2 _int_free() 5.8.3 sYSTRIm()和munmap_chunk(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值