內(nèi)存管理#3

Stack-Based Allocations

要從棧中進行動態(tài)內(nèi)存分配,請使用alloca()系統(tǒng)調(diào)用:

#include <alloca.h>
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 <string.h>
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,則在函數(shù)返回之前不會釋放內(nèi)存祝懂。使用VLA確保在循環(huán)的每一次迭代中釋放內(nèi)存票摇。因此,使用VLA消耗最多n個字節(jié)砚蓬,而Alloca()則消耗n*(n+1)/2個字節(jié)矢门。

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

Approaches to memory allocation in Linux

Manipulating Memory

Setting Bytes

#include <string.h>
void * memset (void *s, int c, size_t n);

對memset()的調(diào)用將從s開始的n個字節(jié)設置為字節(jié)c并返回s。

#include <strings.h>
void bzero (void *s, size_t n);

請注意怜械,bzero()(以及其他b接口)需要頭<strings.h>而不是<string.h>颅和。

Comparing Bytes

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

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

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

0的話相等,否則不相等缕允。
比較兩個結(jié)構(gòu)體的話用memcmp是不安全的, 如下:

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

如果要比較結(jié)構(gòu)體的話,我們應該比較結(jié)構(gòu)體中的每個元素蹭越。

/* 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 <string.h>
void * memmove (void *dst, const void *src, size_t n);
#include <strings.h>
void bcopy (const void *src, void *dst, size_t n);

上面這兩個是是支持overlapping(dst的一部分在src中)
但是下面這個是不支持overlapping的障本,更塊:

#include <string.h>
void * memcpy (void *dst, const void *src, size_t n);

還有一種:

#include <string.h>
void * memccpy (void *dst, const void *src, int c, size_t n);

與memcpy()相同,只是如果函數(shù)在src的前n個字節(jié)內(nèi)找到字節(jié)c,則停止復制驾霜。調(diào)用返回在c之后指向dst中下一個字節(jié)的指針案训,如果沒有找到c,則返回NULL粪糙。 .
最后强霎,您可以使用mempcpy()來逐步遍歷內(nèi)存:

#define GNU_Source
#include<string.h>
void*mempcpy(void*dst,const void*src蓉冈,size_tn)城舞;

mempcpy()函數(shù)執(zhí)行與memcpy()相同的操作。只不過它返回一個指針寞酿,指向上次復制的字節(jié)之后的下一個字節(jié)家夺。如果要將一組數(shù)據(jù)復制到連續(xù)的內(nèi)存位置,這是很有用的伐弹。但它并不是一個改進者 因為返回值僅僅是dst+n拉馋,這個函數(shù)是特定于GNU的。

Searching Bytes

#include <string.h>
void * memchr (const void *s, int c, size_t n);

函數(shù)對s指向的n個字節(jié)的內(nèi)存進行c字符掃描惨好,調(diào)用返回第一個與c匹配的字節(jié)的指針煌茴,如果未找到c,則返回NULL日川。

#define _GNU_SOURCE
#include <string.h>
void * memrchr (const void *s, int c, size_t n);

與memrchr()與memchr()是一樣的景馁,但是是逆序查找。

#define _GNU_SOURCE
#include <string.h>
void * memmem (const void *haystack,
                            size_t haystacklen,
                            const void *needle,
                            size_t needlelen);

在haystack中查找needle逗鸣,找到返回指針合住,找不到返回NULL。

Frobnicating Bytes

#define _GNU_SOURCE
#include <string.h>
void * memfrob (void *s, size_t n);

對memfrob()的調(diào)用掩蓋了從s開始的內(nèi)存的前n個字節(jié)
再次調(diào)用將返回原來的值撒璧。

Locking Memory

Locking Part of an Address Space

#include <sys/mman.h>
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 <sys/mman.h>
int mlockall (int flags);

flags參數(shù)列表:

  • MCL_Current 將當前映射的所有頁面(堆棧卿樱、數(shù)據(jù)段僚害、映射文件等)鎖定到進程的地址空間中。
  • MCL_WORVERY繁调,確保將來映射到地址空間的所有頁也被鎖定在內(nèi)存中萨蚕。
    成功返回0,失敗返回-1蹄胰,并設置errno岳遥。

Unlocking Memory

#include <sys/mman.h>
int munlock (const void *addr, size_t len);
int munlockall (void);

成功返回0, 失敗返回-1裕寨,并且設置errno浩蓉。

Locking Limits

擁有CAP_IPC_LOCK功能的進程可能會將任意數(shù)量的頁面鎖定到內(nèi)存中派继。沒有此功能的進程可能只鎖定RLIMIT_MEMLOCK字節(jié)。
默認情況下捻艳,此資源限制為32KB-足夠大驾窟,可鎖定內(nèi)存中的一個或兩個密碼,但不足以對系統(tǒng)性能產(chǎn)生不利影響认轨。

Is a Page in Physical Mmeory

為了調(diào)試和診斷目的绅络,Linux提供了mincore()函數(shù),該函數(shù)可用于確定給定范圍的內(nèi)存是在物理內(nèi)存中還是交換到磁盤中:

#include <unistd.h>
#include <sys/mman.h>
int mincore (void *start, size_t length, unsigned char *vec);

調(diào)用通過vec返回向量嘁字,并描述從start(必須是頁面對齊)開始的頁面和length字節(jié)的擴展(不需要頁面對齊)恩急。vec中的每個字節(jié) 從描述第一頁的第一個字節(jié)開始,然后線性向前移動拳锚。
vec 必須大于(length ? 1 + page size) / page size
成功返回0假栓, 失敗返回-1,并且設置errno霍掺。

Opportunistic Allocation

Overcommitting and OOM

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末匾荆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子杆烁,更是在濱河造成了極大的恐慌牙丽,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兔魂,死亡現(xiàn)場離奇詭異烤芦,居然都是意外死亡,警方通過查閱死者的電腦和手機析校,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進店門构罗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人智玻,你說我怎么就攤上這事遂唧。” “怎么了吊奢?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵盖彭,是天一觀的道長。 經(jīng)常有香客問我页滚,道長召边,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任裹驰,我火速辦了婚禮隧熙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邦马。我一直安慰自己贱鼻,他們只是感情好宴卖,可當我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布滋将。 她就那樣靜靜地躺著邻悬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪随闽。 梳的紋絲不亂的頭發(fā)上父丰,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天,我揣著相機與錄音掘宪,去河邊找鬼蛾扇。 笑死,一個胖子當著我的面吹牛魏滚,可吹牛的內(nèi)容都是我干的镀首。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼鼠次,長吁一口氣:“原來是場噩夢啊……” “哼更哄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腥寇,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤成翩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赦役,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體麻敌,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年掂摔,在試婚紗的時候發(fā)現(xiàn)自己被綠了术羔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡乙漓,死狀恐怖级历,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情簇秒,我是刑警寧澤鱼喉,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站趋观,受9級特大地震影響扛禽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜皱坛,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一编曼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剩辟,春花似錦掐场、人聲如沸往扔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萍膛。三九已至,卻和暖如春嚷堡,著一層夾襖步出監(jiān)牢的瞬間蝗罗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工蝌戒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留串塑,地道東北人。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓北苟,卻偏偏與公主長得像桩匪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子友鼻,可洞房花燭夜當晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容