美文网首页我爱编程
linux系统编程-内存管理day04-选择合适的内存分配机制&

linux系统编程-内存管理day04-选择合适的内存分配机制&

作者: 桔子满地 | 来源:发表于2018-05-28 10:28 被阅读0次
    • 本节包含了对合适的内存分配机制的选择,以及常见的存储器操作

    选择一个合适的内存分配机制

    • 前面学习了很多内存分配的方式,可能会使我们不知道在一个具体问题中不知道该选择哪一种。(大部分情况下malloc( )总是最好的选择,然而在某些情况下,采用其它的方式会更好一些).
    静态分配 和 自动分配

    有两类是不需要程序员去控制内存分配的:

    • 中分配临时变量
    • 中分配全局变量
    需要程序员控制分配和释放的内存分配方法
    1. malloc( )
    • 优点:简单,方便,最常用
    • 缺点:返回的内存并非用0进行初始化了,只是一段不确定内容的空间,程序员如果想当然的以为是用全0初始化的,则会出问题
    • 用法: char *p = malloc(size);

    1. calloc( )
    • 优点:使数组分配变得容易,用0初始化了内存
    • 缺点:在分配非数组空间时显得较复杂
    • 用法:int * y = calloc(50, sizeof(int));

    1. realloc( )
    • 优点:调整已分配的空间大小
    • 缺点:只能用来调整已分配空间的大小
    • 用法:r = realloc(p, sizeof(struct map));

    1. brk( ) 和 sbrk( )
    • 优点:允许对堆进行深入控制
    • 缺点:对大多数使用者来说过于底层
    • 用法:brk( )会设置数据段的中断点,sbrk( )将数据段末端增加或减少n个字节,其中sbrk(0)返回的是现在断点的地址.

    1. 匿名内存映射
    • 优点:使用简单,可共享,允许开发者调整保护等级并提供建议,适合大空间的分配
    • 缺点:不适合小分配。最优时malloc( )会自动使用匿名内存映射(default情况下,128KB是临界点,临界点可以通过mallopt()来调整在这个临界点)
    • 用法:void p = mmap(NULL, 5121024, PROT_READ|PROT_WRITE, MAP_ANONYMOUS| MAP_PRIVATE, -1, 0);

    1. posix_memalign( )
    • 优点:分配的内存按照任何合理的大小进行对齐
    • 缺点:相对较新,因此可移植性是一个问题;对于对齐的要求不是很迫切的时候,则没有必要使用
    • 用法:
      /* 分配1KB,以256字节对齐 */
      char *buf;
      int ret = posix_memalign(&buf, 256, 1024);

    1. memalign( ) 和 valloc( )
    • 优点:相比posix_memalign( )在其它的Unix系统上更常见
    • 缺点:不是POSIX标准,对齐的控制能力不如posix_memalign( )

    1. alloca( )
    • 优点:最快的分配方式,不需要知道确切的大小,对于小的分配非常适合
    • 缺点:不能返回错误信息,不适合大分配,在一些Unix系统上表现不好
    • 用法:用法与malloc( )一样,但不用自己释放空间. char *p = alloca(1024);

    1. 变长数组VLAs
    • 优点:与alloca( )类似,但在退出此层循环时释放空间,而不是函数返回时
    • 缺点:只能用来分配数组,在一些情况下alloca( )的释放方式更加适用,在其它Unix系统中没有alloca( )常见
    • 用法:
      for (i = 0; i < n; ++i)
      char foo[i + 1];

    • 以上就是对内存分配几种方法的总结,总的来说,malloc( )仍然是最简单最直观的方法,然而有些内存方法,例如基于栈的分配,在linux下能有很好的性能;不过同时,考虑到可移植性问题,要谨慎运用
      ^ ^

    存储器操作

    C语言提供了很多函数进行内存操作。这些函数的功能和字符串操作函数(如strcmp( ) 以及 strcpy( ))类似,但是他们处理的对象是用户提供的内存区域而不是以NULL结尾的字符串。

    • 注意:这些函数都不会返回错误信息。
    1. 字节设置 memset( ):
    #include <string.h>
    void *memset(void *s, int c, size_t n);
    
    • 调用memset( )将把从s指向区域开始的n个字节设置为c
    • 它经常被用来将一块内存清零:
    /* zero out [s, s+256) */
    memset(s, '\0', 256);
    
    • 注:如果你可以使用calloc( )分配内存,那就坚决不要使用memset( )了。因为calloc( )可直接从内存中获取已经清零了的内存,这显然比手工的将每个字节清零要高效。

    2.字节比较 memcmp( ):

    #include <string.h>
    int memcmp(const void *s1, const void *s2, size_t n);
    

    和strcmp( )相似,memcmp( )比较两块内存是否相等。

    • 调用memcmp( )比较s1和s2的头n个字节,如果两块内存相同就返回0,如果s1小于s2就返回一个小于0的数,反之则返回大于0的数。
    • 注意:因为结构体填充的存在,通过memcmp( )来比较两个结构是否相等是不可靠的。如果要比较两个结构体,只能一个个比较结构体中的每一个元素
    1. 字节移动
      3.1 memmove( ):
    #include <string.h>
    void *memmove(void *dst, void *src, size_t n);
    

    memmove( )复制src的前n字节到dst,返回dst。

    • memmove( )可以安全地处理内存区域重叠问题(就是说,dst的一部分在src里面),例如它们允许内存块在一个给定的区域内向上或下移动。

    3.1 不支持内存区域覆盖的memcpy( ):

    #include <string.h>
    void *memcpy(void *dst, const void *src, size_t n);
    
    • 除了dst和src间不能重叠,这个函数基本和memmove( )一样。如果重叠了,函数的结果是未被定义的。

    3.2 memccpy( ):

    • 一个安全的复制函数
    #include <string.h>
    void *memccpy(void *dst, const void *src, int c, size_t n);
    

    memccpy( )和memcpy( )类似,但当它发现字节c在src指向的前n个字节中时会停止拷贝。它返回指向dst中c后一个字节的指针,或者当没有找到c时返回NULL。

    3.3 mempcpy( ):

    • 可以使用mempcpy( )来跨过拷贝的内存
    #define _GNU_SOURCE
    #include <string.h>
    void *mempcpy(void *dst, const void *src, size_t n);
    
    • mempcpy( )和memcpy( )几乎一样,区别在于mempcpy( )返回的是指向被复制的内存的最后一个字节的下一个字节的指针。
    • 当在内存中有连续的一系列数据需要拷贝时它是很有用的,但是它并没有太大的性能提升,因为返回的指针只是dst+n而已。
    • 这个函数是GNU中特有的
    1. 字节搜索
      4.1 memchr( ):
    #include <string.h>
    void *memchr(const void *s, int c, size_t n);
    
    • memchr( )从s指向的区域开的n个字节中寻找c,c将被转换为unsigned char.
    • 函数返回指向第一个匹配c的字节的指针,如果没找到c则返回NULL.

    4.2 memrchr( ):

    #define _GNU_SOURCE
    #include <string.h>
    void *memrchr(const void *s, int c, size_t n);
    
    • memrchr( )与memchr( )类似,不过它是从s指向的内存开始反向搜索n个字节,多的字母r代表reverse的意思
    • memrchr( )是GNU的扩展函数,而不是C语言的一部分

    4.3 memmem( ):

    #define _GNU_SOURCE
    #include <string.h>
    void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
    
    • memmem( )函数在指向长为haystacklen的内存块haystack中查找,并返回第一块和长为needlelen的needle匹配的子块的指针。如果找不到,会返回NULL。
    • 这个函数同样是GNU的扩展函数.
    1. 字节加密
      Linux的C库提供了进行简单数据加密的接口:
    #define _GNU_SOURCE
    #include <string.h>
    void *memfrob(void *s, size_t n);
    
    • memfrob( )函数将s指向的位置开始的n个字节,每个都与42进行异或操作来对数据进行加密。函数返回s。
    • 再次对相同的区域调用memfrob( )可以将其转换回来
    • 用法:memfrob(secret, len);
    • 这个函数用于对数据加密绝对不适合!它仅限于对于字符串的简单处理.
    • 它是GNU标准函数.

    相关文章

      网友评论

        本文标题:linux系统编程-内存管理day04-选择合适的内存分配机制&

        本文链接:https://www.haomeiwen.com/subject/ddywjftx.html