内存管理#3

Stack-Based Allocations

要从栈中进行动态内存分配,请使用alloca()系统调用:

#include 
void *alloca(size_t size);

不需要free。

int open_sysconf (const char *file, int flags, int mode) {
    const char *etc = SYSCONF_DIR; /* "/etc/" */
    char *name;
    name = alloca (strlen (etc) + strlen (file) + 1);
    strcpy (name, etc);
    strcat (name, file);
    return open (name, flags, mode);
}
int open_sysconf (const char *file, int flags, int mode) {
    const char *etc = SYSCONF_DIR; /* "/etc/" */
    char *name;
    int fd;
    name = malloc (strlen (etc) + strlen (file) + 1);
    if (!name) {
        perror ("malloc");
        return −1;
     }
    strcpy (name, etc);    
    strcat (name, file);
    fd = open (name, flags, mode);
    free (name);
    return fd;
 }

如果您的程序必须保持可移植性,则应该避免alloca()。
在Linux上,alloca()是一个非常有用和利用不足的工具。
不要这么使用就行:

/* DO NOT DO THIS! */
ret = foo (x, alloca (10));

Duplicating String on the Stack

/* we want to duplicate 'song' */
char *dup;
dup = alloca (strlen (song) + 1);
strcpy (dup, song);
/* manipulate 'dup'... */
return; /* 'dup' is automatically freed */
#define _GNU_SOURCE
#include 
char * strdupa (const char *s);
char * strndupa (const char *s, size_t n);

他们是一样的。

Variable-Length Arrays(VLA)

//典型用法
for (i = 0; i < n; ++i) {
    char foo[i + 1];
    /* use 'foo'... */
}

如果我们使用的是alloca()而不是VLA,则在函数返回之前不会释放内存。使用VLA确保在循环的每一次迭代中释放内存。因此,使用VLA消耗最多n个字节,而Alloca()则消耗n*(n+1)/2个字节。

int open_sysconf (const char *file, int flags, int mode) {
    const char *etc; = SYSCONF_DIR; /* "/etc/" */
    char name[strlen (etc) + strlen (file) + 1];
    strcpy (name, etc);
    strcat (name, file);
    return open (name, flags, mode);
}

Choosing a Memory Allocation Mechansim

内存管理#3_第1张图片
Approaches to memory allocation in Linux

Manipulating Memory

Setting Bytes

#include 
void * memset (void *s, int c, size_t n);

对memset()的调用将从s开始的n个字节设置为字节c并返回s。

#include 
void bzero (void *s, size_t n);

请注意,bzero()(以及其他b接口)需要头而不是

Comparing Bytes

#include 
int memcmp (const void *s1, const void *s2, size_t n);

s1 = s2: return 0
s1 < s2: return <0
s1 > s2: return >0

#include 
int bcmp (const void *s1, const void *s2, size_t n);

0的话相等,否则不相等。
比较两个结构体的话用memcmp是不安全的, 如下:

/* are two dinghies identical? (BROKEN) */
int compare_dinghies (struct dinghy *a, struct dinghy *b) {
    return memcmp (a, b, sizeof (struct dinghy));
}

如果要比较结构体的话,我们应该比较结构体中的每个元素。

/* are two dinghies identical? */
int compare_dinghies (struct dinghy *a, struct dinghy *b) {
    int ret;
    if (a->nr_oars < b->nr_oars)
        return −1;
    if (a->nr_oars > b->nr_oars)
        return 1;
    ret = strcmp (a->boat_name, b->boat_name);
    if (ret)
        return ret;
    /* and so on, for each member... */
}

Moving Bytes

#include 
void * memmove (void *dst, const void *src, size_t n);
#include 
void bcopy (const void *src, void *dst, size_t n);

上面这两个是是支持overlapping(dst的一部分在src中)
但是下面这个是不支持overlapping的,更块:

#include 
void * memcpy (void *dst, const void *src, size_t n);

还有一种:

#include 
void * memccpy (void *dst, const void *src, int c, size_t n);

与memcpy()相同,只是如果函数在src的前n个字节内找到字节c,则停止复制。调用返回在c之后指向dst中下一个字节的指针,如果没有找到c,则返回NULL。 .
最后,您可以使用mempcpy()来逐步遍历内存:

#define GNU_Source
#include
void*mempcpy(void*dst,const void*src,size_tn);

mempcpy()函数执行与memcpy()相同的操作。只不过它返回一个指针,指向上次复制的字节之后的下一个字节。如果要将一组数据复制到连续的内存位置,这是很有用的。但它并不是一个改进者 因为返回值仅仅是dst+n,这个函数是特定于GNU的。

Searching Bytes

#include 
void * memchr (const void *s, int c, size_t n);

函数对s指向的n个字节的内存进行c字符扫描,调用返回第一个与c匹配的字节的指针,如果未找到c,则返回NULL。

#define _GNU_SOURCE
#include 
void * memrchr (const void *s, int c, size_t n);

与memrchr()与memchr()是一样的,但是是逆序查找。

#define _GNU_SOURCE
#include 
void * memmem (const void *haystack,
                            size_t haystacklen,
                            const void *needle,
                            size_t needlelen);

在haystack中查找needle,找到返回指针,找不到返回NULL。

Frobnicating Bytes

#define _GNU_SOURCE
#include 
void * memfrob (void *s, size_t n);

对memfrob()的调用掩盖了从s开始的内存的前n个字节
再次调用将返回原来的值。

Locking Memory

Locking Part of an Address Space

#include 
int mlock (const void *addr, size_t len);

成功返回0, 失败返回-1,并设置errno。

int ret;
/* lock 'secret' in memory */
ret = mlock (secret, strlen (secret));
if (ret)
    perror ("mlock");

Locking All of an Address Space

#include 
int mlockall (int flags);

flags参数列表:

  • MCL_Current 将当前映射的所有页面(堆栈、数据段、映射文件等)锁定到进程的地址空间中。
  • MCL_WORVERY,确保将来映射到地址空间的所有页也被锁定在内存中。
    成功返回0,失败返回-1,并设置errno。

Unlocking Memory

#include 
int munlock (const void *addr, size_t len);
int munlockall (void);

成功返回0, 失败返回-1,并且设置errno。

Locking Limits

拥有CAP_IPC_LOCK功能的进程可能会将任意数量的页面锁定到内存中。没有此功能的进程可能只锁定RLIMIT_MEMLOCK字节。
默认情况下,此资源限制为32KB-足够大,可锁定内存中的一个或两个密码,但不足以对系统性能产生不利影响。

Is a Page in Physical Mmeory

为了调试和诊断目的,Linux提供了mincore()函数,该函数可用于确定给定范围的内存是在物理内存中还是交换到磁盘中:

#include 
#include 
int mincore (void *start, size_t length, unsigned char *vec);

调用通过vec返回向量,并描述从start(必须是页面对齐)开始的页面和length字节的扩展(不需要页面对齐)。vec中的每个字节 从描述第一页的第一个字节开始,然后线性向前移动。
vec 必须大于(length − 1 + page size) / page size
成功返回0, 失败返回-1,并且设置errno。

Opportunistic Allocation

Overcommitting and OOM

你可能感兴趣的:(内存管理#3)