chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

淺析Slub分配器的設(shè)計(jì)需求與設(shè)計(jì)思想

xCb1_yikoulinux ? 來(lái)源:人人都是極客 ? 作者:賀東升 ? 2022-07-22 11:59 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

slab分配器設(shè)計(jì)的需求

Linux內(nèi)核的內(nèi)存子系統(tǒng)中,伙伴系統(tǒng)無(wú)疑處于內(nèi)存管理的核心地帶,但是如果將內(nèi)存管理從邏輯上分層,它的位置則處于最底層。Buddy是所有物理內(nèi)存的管家,不論使用何種接口申請(qǐng)內(nèi)存都要經(jīng)由伙伴系統(tǒng)進(jìn)行分配。但是,伙伴系統(tǒng)管理的物理內(nèi)存是以頁(yè)為單位,以4K頁(yè)為例,它也包含了4096個(gè)字節(jié)。但是無(wú)論是內(nèi)核自己還是用戶(hù)程序,在日常的使用中都很少會(huì)需要使用四千多字節(jié)大小的內(nèi)存。試想如果我們僅需要為10個(gè)字符的字符串分配內(nèi)存,但是伙伴系統(tǒng)卻給了我們一頁(yè),那這一頁(yè)剩余沒(méi)有使用的內(nèi)存就浪費(fèi)了,而且這個(gè)浪費(fèi)近乎奢侈。除了浪費(fèi)的問(wèn)題, 還有一個(gè)更需要關(guān)心的問(wèn)題是,在這樣的分配情況下,如果分配非常頻繁,系統(tǒng)可能很快就會(huì)面臨嚴(yán)重的碎片化問(wèn)題。因?yàn)轭l繁使用的數(shù)據(jù)結(jié)構(gòu)也會(huì)頻繁的分配和釋放,加速生產(chǎn)內(nèi)存碎片。另外,直接調(diào)用伙伴系統(tǒng)的操作對(duì)系統(tǒng)的數(shù)據(jù)和指令高速緩存也有很大的影響。所以,基于以上的原因,也源于現(xiàn)實(shí)需求,內(nèi)核需要一種輕量的、快速的、靈活的新型內(nèi)存分配器,最主要的是,它可以提供小塊內(nèi)存的分配。為了實(shí)現(xiàn)這樣的小內(nèi)存分配器,Sun公司的J.Bonwick首先在Solaris 2.4中設(shè)計(jì)并實(shí)現(xiàn)了slab分配器,并對(duì)其開(kāi)源。在Linux中也實(shí)現(xiàn)了具有相同的基本設(shè)計(jì)思想的同名分配器slab。

slab、slob和slub關(guān)系

slab、slob和slub都是小內(nèi)存分配器,slab是slob和slub實(shí)現(xiàn)的基礎(chǔ),而slob和slub是針對(duì)slab在不同場(chǎng)景下的優(yōu)化版本。在slab引入Linux的很多年內(nèi),其都是Linux內(nèi)核管理對(duì)象緩沖區(qū)的主流算法。并且由于slab的實(shí)現(xiàn)非常復(fù)雜,很長(zhǎng)一段時(shí)間內(nèi)都少有對(duì)它的改動(dòng)。隨著多處理器的發(fā)展和NUMA架構(gòu)的廣泛應(yīng)用,slab的不足也逐漸顯現(xiàn)。slab的緩存隊(duì)列管理復(fù)雜,其用于管理的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)開(kāi)銷(xiāo)大,對(duì)NUMA支持復(fù)雜,slab著色機(jī)制效果不明顯。這些不足讓slab很難在兩種場(chǎng)景下提供最優(yōu)的性能:小型嵌入式系統(tǒng)和配備有大量物理內(nèi)存的大規(guī)模并行系統(tǒng)。對(duì)于小型嵌入式系統(tǒng)來(lái)說(shuō),slab分配器的代碼量和復(fù)雜性都太高;對(duì)于大規(guī)模并行系統(tǒng),slab用于自身管理的數(shù)據(jù)結(jié)構(gòu)就需要占用很多G字節(jié)內(nèi)存。針對(duì)slab的不足,內(nèi)核開(kāi)發(fā)人員Christoph Lameter在在內(nèi)核版本2.6開(kāi)發(fā)期間,引入了新的Slub分配器。Slub簡(jiǎn)化了slab一些復(fù)雜的設(shè)計(jì),但保持slab的基本設(shè)計(jì)思想。同時(shí),一種新的針對(duì)小型嵌入式系統(tǒng)的分配器slob也被引入,為了適應(yīng)嵌入式系統(tǒng)的特點(diǎn),slob進(jìn)行了特別的優(yōu)化,以大幅減少代碼量(slob只有大約600行代碼)。

slab層在內(nèi)存管理子系統(tǒng)的層次

slab層可以理解為一個(gè)通用層,其包含了slab、slob和slub,至于底層具體使用哪種分配器可以通過(guò)配置內(nèi)核選項(xiàng)進(jìn)行選擇。對(duì)于內(nèi)核的其他模塊,則不需要關(guān)注底層使用了哪個(gè)分配器。因?yàn)闉榱吮WC內(nèi)核的其他模塊都可以無(wú)縫遷移到Slub/slob,所有分配器的接口都是相同的,它們都實(shí)現(xiàn)了一組特定的接口用于內(nèi)存分配。下圖為Slab層在內(nèi)存管理中的層次圖:

1258c71e-0971-11ed-ba43-dac502259ad0.png

邏輯上看,slab層位于伙伴系統(tǒng)之上。因?yàn)锽uddy是最底層的分配器,Slub需要先向Buddy申請(qǐng)內(nèi)存,而不能越過(guò)Buddy獲取page。從Buddy申請(qǐng)到內(nèi)存后,Slub才可以對(duì)其進(jìn)行自己的操作。

slub分配器框架

下圖是在讀完宋牧春大俠的《圖解Slub》后,我也總結(jié)了一張Slub分配器框架圖,可以大致的看到Slub的框架。Slub的框架如下圖(圖片很大,可以放大):

126c0748-0971-11ed-ba43-dac502259ad0.png

這篇文章中用了一個(gè)通俗易懂的例子來(lái)介紹Slub的工作原理,我覺(jué)的這個(gè)例子很恰當(dāng),所以這里繼續(xù)借舉一下。

每個(gè)數(shù)組元素對(duì)應(yīng)一種大小的內(nèi)存,可以把一個(gè)kmem_cache結(jié)構(gòu)體看做是一個(gè)特定大小內(nèi)存的零售商,整個(gè)Slub系統(tǒng)中有很多個(gè)這樣的零售商,每個(gè)“零售商”只“零售”特定大小的內(nèi)存,例如:有的“零售商”只"零售"8Byte大小的內(nèi)存,有的只”零售“16Byte大小的內(nèi)存?!詌uken.《linux內(nèi)核內(nèi)存管理slub算法(一)原理》

Slub的工作原理和日常生產(chǎn)生活的產(chǎn)銷(xiāo)環(huán)節(jié)很類(lèi)似,所以為了清晰直觀(guān)的看到其工作原理,我把這個(gè)過(guò)程畫(huà)了一幅圖來(lái)表示,如下圖:

1287e90e-0971-11ed-ba43-dac502259ad0.png

每個(gè)零售商(kmem_cache)有兩個(gè)“部門(mén)”,一個(gè)是“倉(cāng)庫(kù)”:kmem_cache_node,一個(gè)“營(yíng)業(yè)廳”:kmem_cache_cpu?!盃I(yíng)業(yè)廳”里只保留一個(gè)slab,只有在營(yíng)業(yè)廳(kmem_cache_cpu)中沒(méi)有空閑內(nèi)存的情況下才會(huì)從倉(cāng)庫(kù)中換出其他的slab。所謂slab就是零售商(kmem_cache)批發(fā)的連續(xù)的整頁(yè)內(nèi)存,零售商把這些整頁(yè)的內(nèi)存分成許多小內(nèi)存,然后分別“零售”出去,一個(gè)slab可能包含多個(gè)連續(xù)的內(nèi)存頁(yè)。slab的大小和零售商有關(guān)?!詌uken.《linux內(nèi)核內(nèi)存管理slub算法(一)原理》

總的來(lái)說(shuō),Slub就相當(dāng)于零售商,它從伙伴系統(tǒng)“批發(fā)”內(nèi)存,然后再零售出去。

slub的重要數(shù)據(jù)結(jié)構(gòu)

  • kmem_cache
structkmem_cache{
structkmem_cache_cpu__percpu*cpu_slab;
/*Usedforretrivingpartialslabsetc*/
unsignedlongflags;
unsignedlongmin_partial;
/*size=object_size+對(duì)象后面下個(gè)空閑對(duì)象的指針的size*/
intsize;/*Thesizeofanobjectincludingmetadata*/
intobject_size;/*Thesizeofanobjectwithoutmetadata*/
/*object首地址+offset=下一個(gè)空閑對(duì)象的指針地址*/
intoffset;/*Freepointeroffset.*/
intcpu_partial;/*Numberofpercpupartialobjectstokeeparound*/
/*
*oo表示存放最優(yōu)slab的order和object的數(shù)量
*低16位表示對(duì)象數(shù),高16位表示slab的order
*/
structkmem_cache_order_objectsoo;
/*Allocationandfreeingofslabs*/
structkmem_cache_order_objectsmax;
/*
*最小slab只需要足夠存放一個(gè)對(duì)象。當(dāng)設(shè)備長(zhǎng)時(shí)間運(yùn)行以后,內(nèi)存碎片化嚴(yán)重,
*分配連續(xù)物理頁(yè)很難成功,如果分配最優(yōu)slab失敗,就分配最小slab。
*/
structkmem_cache_order_objectsmin;
gfp_tallocflags;/*gfpflagstouseoneachalloc*/
intrefcount;/*Refcountforslabcachedestroy*/
void(*ctor)(void*);
intinuse;/*Offsettometadata*/
intalign;/*Alignment*/
//當(dāng)slab長(zhǎng)度不是對(duì)象長(zhǎng)度的整數(shù)倍的時(shí)候,尾部有剩余部分,保存在reserved中
intreserved;/*Reservedbytesattheendofslabs*/
constchar*name;/*Name(onlyfordisplay!)*/
structlist_headlist;/*Listofslabcaches*/
intred_left_pad;/*Leftredzonepaddingsize*/
#ifdefCONFIG_SYSFS
structkobjectkobj;/*Forsysfs*/
#endif
#ifdefCONFIG_MEMCG
structmemcg_cache_paramsmemcg_params;
intmax_attr_size;/*forpropagation,maximumsizeofastoredattr*/
#ifdefCONFIG_SYSFS
structkset*memcg_kset;
#endif
#endif
#ifdefCONFIG_NUMA
/*
*Defragmentationbyallocatingfromaremotenode.
*/
intremote_node_defrag_ratio;
#endif
#ifdefCONFIG_SLAB_FREELIST_RANDOM
unsignedint*random_seq;
#endif
#ifdefCONFIG_KASAN
structkasan_cachekasan_info;
#endif
structkmem_cache_node*node[MAX_NUMNODES];/*每個(gè)NUMA節(jié)點(diǎn)都有一個(gè)kmem_cache_node*/
};

根據(jù)是否打開(kāi)Slub Debug,next object指針可以有兩種方式放置,如果打開(kāi)了Slub Debug,則采用指針外置式;反之,采用指針內(nèi)置式。兩種指針?lè)胖梅绞饺缦聢D:

  • 指針外置式
129cd080-0971-11ed-ba43-dac502259ad0.png
  • 指針內(nèi)置式
12a94b1c-0971-11ed-ba43-dac502259ad0.png

指針內(nèi)置式的方法實(shí)際上是復(fù)用了object的前8個(gè)字節(jié),因?yàn)樵趏bject被分配出去之前,這一段內(nèi)存具體存放什么內(nèi)容并不重要,所以可以利用這一段內(nèi)存來(lái)保存下一個(gè)free object的地址。

  • kmem_cache_cpu
structkmem_cache_cpu{
/*指向下一個(gè)空閑的object,用于快速找到可用對(duì)象*/
void**freelist;/*Pointertonextavailableobject*/
/*
*要保證tid和kmem_cache是由同一個(gè)CPU訪(fǎng)問(wèn)。
*開(kāi)啟了內(nèi)核搶占后,訪(fǎng)問(wèn)tid和kmem_cache的CPU可能不是同一個(gè)CPU,
*所以要檢查是否匹配,直到它們是由同一個(gè)CPU進(jìn)行訪(fǎng)問(wèn)
*/
unsignedlongtid;/*Globallyuniquetransactionid*/
/*指向當(dāng)前使用的slab*/
structpage*page;/*Theslabfromwhichweareallocating*/
/*指向當(dāng)前cpu上緩存的部分空閑slab鏈表*/
structpage*partial;/*Partiallyallocatedfrozenslabs*/
#ifdefCONFIG_SLUB_STATS
/*
*記錄對(duì)slab操作的狀態(tài)變化,這個(gè)stat非常重要,
*通過(guò)這個(gè)stat就大概了解object從申請(qǐng)到釋放經(jīng)過(guò)了哪些步驟
*/
unsignedstat[NR_SLUB_STAT_ITEMS];
#endif
};
  • kmem_cache_node
structkmem_cache_node{
spinlock_tlist_lock;
/*此處省略掉SLAB的配置*/
#ifdefCONFIG_SLUB
/*掛入kmem_cache_node中的slab數(shù)量*/
unsignedlongnr_partial;
/*指向當(dāng)前內(nèi)存節(jié)點(diǎn)上的部分空閑slab鏈表*/
structlist_headpartial;
#ifdefCONFIG_SLUB_DEBUG
atomic_long_tnr_slabs;
atomic_long_ttotal_objects;
structlist_headfull;
#endif
#endif
};

page中描述Slub信息的字段:

structpage{
/*如果flag設(shè)置成PG_slab,表示頁(yè)屬于slub分配器*/
unsignedlongflags;
union{
structaddress_space*mapping;
/*指向當(dāng)前slab中第一個(gè)object*/
void*s_mem;/*slabfirstobject*/
atomic_tcompound_mapcount;/*firsttailpage*/
};
union{
pgoff_tindex;/*Ouroffsetwithinmapping.*/
/*指向當(dāng)前slab中第一個(gè)空閑的object*/
void*freelist;/*sl[aou]bfirstfreeobject*/
};
union{
unsignedcounters;
struct{
union{
atomic_t_mapcount;
unsignedintactive;/*SLAB*/
struct{/*SLUB*/
/*該slab中已經(jīng)分配使用的object數(shù)量*/
unsignedinuse:16;
/*該slab中的所有object數(shù)量*/
unsignedobjects:15;
/*
*如果slab在kmem_cache_cpu中,表示處于凍結(jié)狀態(tài);
*如果slab在kmem_cache_node的部分空閑slab鏈表中,表示處于解凍狀態(tài)
*/
unsignedfrozen:1;
};
intunits;/*SLOB*/
};
atomic_t_refcount;
};
};
union{
/*作為鏈表節(jié)點(diǎn)加入到kmem_cache_node的部分空閑slab鏈表中
structlist_headlru;/*Pageoutlist*/
structdev_pagemap*pgmap;
struct{/*slubpercpupartialpages*/
structpage*next;/*Nextpartialslab*/
intpages;/*Nrofpartialslabsleft*/
intpobjects;/*Approximate#ofobjects*/
};
structrcu_headrcu_head;
struct{
unsignedlongcompound_head;/*Ifbitzeroisset*/
unsignedintcompound_dtor;
unsignedintcompound_order;
};
};
union{
unsignedlongprivate;
structkmem_cache*slab_cache;/*SL[AU]B:Pointertoslab*/
};
......
}

Slub的分配過(guò)程

Slub的分配流程大致如下:首先從kmem_cache_cpu中分配,如果沒(méi)有則從kmem_cache_cpu的partial鏈表分配,如果還沒(méi)有則從kmem_cache_node中分配,如果kmem_cache_node中也沒(méi)有,則需要向伙伴系統(tǒng)申請(qǐng)內(nèi)存。

12b7e7bc-0971-11ed-ba43-dac502259ad0.png

Slub的分配接口是kmem_cache_malloc()。其分配object的流程大概如下:首先在kmem_cache_cpu所使用的slab中查找free object,如果當(dāng)前slab中有free object,則返回這個(gè)object。如果當(dāng)前slab沒(méi)有free object,就要看Slub是否開(kāi)啟了kmem_cache_cpu的Partial隊(duì)列,如果開(kāi)啟了partial隊(duì)列,就在Partial隊(duì)列中查看有沒(méi)有free object的slab,如果有的話(huà)就選定這個(gè)slab,并返回其free object。如果kmem_cache_cpu的partial鏈表中也沒(méi)有擁有free object的slab,則在kmem_cache_node中查找。如果kmem_cache_node中的slab有free object,則選定這個(gè)slab并返回free object。如果kmem_cache_node中也沒(méi)有free object,則需要向伙伴系統(tǒng)申請(qǐng)內(nèi)存,制作新的slab。

創(chuàng)建slab緩存(kmem_cache)的函數(shù)分析

斗膽分析一下slab緩存的創(chuàng)建過(guò)程,新手小白分析內(nèi)核代碼,分析的可能不夠深度和完整,如有不對(duì)還請(qǐng)各路高手指教,提前謝過(guò)。

函數(shù)調(diào)用流程:

kmem_cache_create()
——>kmem_cache_create_usercopy()
——>create_cache()
——>__kmem_cache_create()
——>kmem_cache_open()

下面是每個(gè)函數(shù)的主干分析,代碼有精簡(jiǎn)。

kmem_cache_create():

kmem_cache_create()里繼續(xù)調(diào)用了kmem_cache_create_usercopy()。

kmem_cache_create(){
returnkmem_cache_create_usercopy(name,size,align,flags,0,0,ctor);
}

kmem_cache_create_usercopy():

kmem_cache_create_usercopy(){
structkmem_cache*s=NULL;
constchar*cache_name;

/*
*Someallocatorswillconstraintthesetofvalidflagstoasubset
*ofallflags.WeexpectthemtodefineCACHE_CREATE_MASKinthis
*case,andwe'lljustprovidethemwithasanitizedversionofthe
*passedflags.
*/
flags&=CACHE_CREATE_MASK;

/*定義這個(gè)緩存的名字,用于在/proc/slabinfo中顯示*/
cache_name=kstrdup_const(name,GFP_KERNEL);

/*kmem_cache結(jié)構(gòu),并返回其地址*/
s=create_cache(cache_name,size,
calculate_alignment(flags,align,size),
flags,useroffset,usersize,ctor,NULL,NULL);

returns;
}

create_cache():

create_cache(){
structkmem_cache*s;
interr;

/*為kmem_cache結(jié)構(gòu)申請(qǐng)一段內(nèi)存并清零*/
s=kmem_cache_zalloc(kmem_cache,GFP_KERNEL);

/*初始化kmem_cache結(jié)構(gòu)的部分成員*/
s->name=name;
s->size=s->object_size=object_size;
s->align=align;
s->ctor=ctor;
s->useroffset=useroffset;
s->usersize=usersize;

/*核心函數(shù),slub/slab/slob都實(shí)現(xiàn)了這個(gè)函數(shù)*/
err=__kmem_cache_create(s,flags);

/*將新創(chuàng)建的kmem_cache加入slabcaches鏈表*/
list_add(&s->list,&slab_caches);

returns;
}

__kmem_cache_create():

__kmem_cache_create(){
interr;

/*在kmem_cache_open中處理剩余的結(jié)構(gòu)成員,如min_partial、cpu_partial等*/
err=kmem_cache_open(s,flags);
}

kmem_cache_open():

kmem_cache_open(){
/*設(shè)置kmem_cache中的min_partial,它表示kmem_cache_node中partial鏈表可掛入的slab數(shù)量*/
set_min_partial(s,ilog2(s->size)/2);

/*設(shè)置kmem_cache中的cpu_partial,它表示percpupartial上所有slab中freeobject總數(shù)*/
set_cpu_partial(s);

/*為每個(gè)節(jié)點(diǎn)分配kmem_cache_node*/
if(!init_kmem_cache_nodes(s))
gotoerror;

/*為kmem_cache_cpu變量創(chuàng)建每CPU副本*/
if(alloc_kmem_cache_cpus(s))
return0;
}

分配對(duì)象(object)的函數(shù)分析

函數(shù)調(diào)用流程:

kmem_cache_alloc()
——>slab_alloc()
——>slab_alloc_node()
——>__slab_alloc()
——>___slab_alloc()

kmem_cache_alloc():

kmem_cache_alloc(){
/*直接調(diào)用slab_alloc*/
void*ret=slab_alloc(s,gfpflags,_RET_IP_);

returnret;
}

slab_alloc():

slab_alloc(){
returnslab_alloc_node(s,gfpflags,NUMA_NO_NODE,addr);
}

slab_alloc_node():

slab_alloc_node(){
void*object;
structkmem_cache_cpu*c;
structpage*page;

redo:
/*
*要保證tid和kmem_cache是由同一個(gè)CPU訪(fǎng)問(wèn)。但是如果配置了CONFIG_PREEMPT = y,
*即開(kāi)啟了內(nèi)核搶占后,訪(fǎng)問(wèn)tid和kmem_cache的CPU可能不是同一個(gè)CPU,所以要檢查
*是否匹配,直到它們是由同一個(gè)CPU進(jìn)行訪(fǎng)問(wèn)。
*
*內(nèi)核態(tài)搶占的時(shí)機(jī)是:
*1.中斷處理函數(shù)返回內(nèi)核空間之前會(huì)檢查請(qǐng)求重新調(diào)度的標(biāo)志(TIF_NEED_RESCHED),
*如果置位則調(diào)用preempt_schedule_irq()執(zhí)行搶占。
* 2. 當(dāng)內(nèi)核從non-preemptible(禁止搶占)狀態(tài)變成preemptible(允許搶占)的時(shí)候。
*/
do{
tid=this_cpu_read(s->cpu_slab->tid);/*訪(fǎng)問(wèn)當(dāng)前CPU的perCPU變量的副本的tid*/
c=raw_cpu_ptr(s->cpu_slab);
}while(IS_ENABLED(CONFIG_PREEMPT)&&/*檢查是否開(kāi)啟了內(nèi)核搶占*/
unlikely(tid!=READ_ONCE(c->tid)));

barrier();/*內(nèi)存屏障,消除指令亂序執(zhí)行的影響*/

object=c->freelist;/*下一個(gè)freeobject的地址*/
page=c->page;/*當(dāng)前使用的slab*/
if(unlikely(!object||!node_match(page,node))){
/*調(diào)用核心函數(shù)__slab_alloc()*/
object=__slab_alloc(s,gfpflags,node,addr,c);
stat(s,ALLOC_SLOWPATH);
}else{
void*next_object=get_freepointer_safe(s,object);

if(unlikely(!this_cpu_cmpxchg_double(
s->cpu_slab->freelist,s->cpu_slab->tid,
object,tid,
next_object,next_tid(tid)))){

note_cmpxchg_failure("slab_alloc",s,tid);
gotoredo;
}
prefetch_freepointer(s,next_object);
stat(s,ALLOC_FASTPATH);
}

maybe_wipe_obj_freeptr(s,object);

/*如果gfpflags標(biāo)志需要對(duì)object對(duì)象的內(nèi)存清零*/
if(unlikely(slab_want_init_on_alloc(gfpflags,s))&&object)
memset(object,0,s->object_size);

slab_post_alloc_hook(s,gfpflags,1,&object);

returnobject;
}

__slab_alloc():

__slab_alloc(){
void*p;
unsignedlongflags;

/*
*關(guān)中斷。關(guān)閉當(dāng)前處理器上的所有中斷處理
*
*local_irq_save()將當(dāng)前的中斷狀態(tài)(開(kāi)或關(guān))
*保存在flags中然后再禁用處理器上的中斷。
*
*與local_irq_save不同,local_irq_disable()
*不保存狀態(tài)而關(guān)閉本地處理器的中斷服務(wù)。
*/
local_irq_save(flags);
#ifdefCONFIG_PREEMPT
/*
*在關(guān)中斷之前,可能已經(jīng)被搶占并被調(diào)度在不同的CPU上,
*所以需要重新加載CPU區(qū)域的指針。
*/
c=this_cpu_ptr(s->cpu_slab);
#endif
/*調(diào)用核心函數(shù)___slab_alloc()*/
p=___slab_alloc(s,gfpflags,node,addr,c);

/*
*恢復(fù)本地處理器的中斷。
*
*local_irq_restore()將local_irq_save()保存的狀態(tài)值(flags)恢復(fù),
*注意是恢復(fù)之前的中斷狀態(tài),不一定會(huì)開(kāi)啟中斷。如果之前的狀態(tài)是
*開(kāi)中斷,就打開(kāi)中斷;如果之前的狀態(tài)是關(guān)中斷,就關(guān)閉中斷。
*而local_irq_enable()會(huì)無(wú)條件開(kāi)啟中斷,所以可能會(huì)破壞之前的中
*斷環(huán)境。所以local_irq_restore()比local_irq_enable()更安全。
*/
local_irq_restore(flags);

returnp;
}

slub的frozen(凍結(jié))和unfrozen(解凍)

如果cpu1的kcmem_cache_cpu的slab是frozen, 那么cpu1可以從該slab中取出或放回obj,但是cpu2不能從該slab中取obj, 只能把obj還給該slab。另外,cpu partial上的slab都是frozen狀態(tài)。node partial上的slab都是unfrozen。耗盡kmem_cache_cpu的slab的obj后解凍slab。


審核編輯:劉清
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    20071

    瀏覽量

    243044
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11576

    瀏覽量

    216832
  • 分配器
    +關(guān)注

    關(guān)注

    0

    文章

    210

    瀏覽量

    26750
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    317

    瀏覽量

    22886
  • Slub
    +關(guān)注

    關(guān)注

    0

    文章

    1

    瀏覽量

    788

原文標(biāo)題:Slub分配器的來(lái)龍去脈

文章出處:【微信號(hào):yikoulinux,微信公眾號(hào):一口Linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    介紹一款一分十四的編碼器信號(hào)分配器

    電子元器件分配器儀器儀表
    西安同步電子科技有限公司
    發(fā)布于 :2025年10月14日 19:29:12

    電機(jī)同步編碼脈沖分配器

    電子元器件分配器儀器儀表
    西安同步電子科技有限公司
    發(fā)布于 :2025年10月14日 19:27:34

    如何挑選合適的頻標(biāo)分配器

    電子元器件分配器儀器儀表
    西安同步電子科技有限公司
    發(fā)布于 :2025年10月14日 19:15:41

    頻率信號(hào)分配器功能介紹

    電子元器件分配器儀器儀表
    西安同步電子科技有限公司
    發(fā)布于 :2025年10月14日 19:05:39

    頻標(biāo)分配器

    電子元器件分配器儀器儀表
    西安同步電子科技有限公司
    發(fā)布于 :2025年10月14日 18:59:11

    ?CDCL1810A 高性能時(shí)鐘分配器技術(shù)文檔總結(jié)

    CDCL1810A 是一款高性能時(shí)鐘分配器??删幊谭诸l器 P0 和 P1,對(duì)輸出頻率與輸入頻率的比值具有很高的靈活性: F ~外~ = F ~在~ /P,其中 P (P0,P1) = 1, 2, 4
    的頭像 發(fā)表于 09-14 11:02 ?795次閱讀
    ?CDCL1810A 高性能時(shí)鐘<b class='flag-5'>分配器</b>技術(shù)文檔總結(jié)

    低損耗雙向功率分配器/合路器 2.2–2.8 GHz skyworksinc

    電子發(fā)燒友網(wǎng)為你提供()低損耗雙向功率分配器/合路器 2.2–2.8 GHz相關(guān)產(chǎn)品參數(shù)、數(shù)據(jù)手冊(cè),更有低損耗雙向功率分配器/合路器 2.2–2.8 GHz的引腳圖、接線(xiàn)圖、封裝手冊(cè)、中文資料、英文
    發(fā)表于 07-30 18:34
    低損耗雙向功率<b class='flag-5'>分配器</b>/合路器 2.2–2.8 GHz skyworksinc

    五路有源功率分配器 skyworksinc

    電子發(fā)燒友網(wǎng)為你提供()五路有源功率分配器相關(guān)產(chǎn)品參數(shù)、數(shù)據(jù)手冊(cè),更有五路有源功率分配器的引腳圖、接線(xiàn)圖、封裝手冊(cè)、中文資料、英文資料,五路有源功率分配器真值表,五路有源功率分配器管腳
    發(fā)表于 07-30 18:33
    五路有源功率<b class='flag-5'>分配器</b> skyworksinc

    九航星達(dá)KS-DVI0104型4通道DVI分配器使用手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《九航星達(dá)KS-DVI0104型4通道DVI分配器使用手冊(cè).doc》資料免費(fèi)下載
    發(fā)表于 07-21 14:45 ?0次下載

    九航星達(dá)KS-DVI0102型2通道DVI分配器使用手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《九航星達(dá)KS-DVI0102型2通道DVI分配器使用手冊(cè).doc》資料免費(fèi)下載
    發(fā)表于 07-16 17:35 ?0次下載

    802-4-0.252,N型母頭功率分配器/合路器MECA

    802-4-0.252,N型母頭功率分配器/合路器MECA802-4-0.252是一款由MECA生產(chǎn)的N型母頭射頻功率分配器/合路器,802-4-0.252功率分配器/合路器平均額定功率為2瓦,頻率
    發(fā)表于 05-27 08:51

    MAX9174/MAX9175 670MHz、LVDS至LVDS和任意邏輯至LVDS 1:2分配器中文手冊(cè)

    MAX9174/MAX9175是670MHz低抖動(dòng)、低扭曲的1:2分配器,尤其適合于保護(hù)切換、環(huán)回、時(shí)鐘和數(shù)據(jù)分配。這些器件具有1.0ps~(RMS)~ (最大)的超低隨機(jī)抖動(dòng),保證在那些定時(shí)誤差極為敏感的高速鏈路中可靠工作。
    的頭像 發(fā)表于 05-19 09:23 ?539次閱讀
    MAX9174/MAX9175 670MHz、LVDS至LVDS和任意邏輯至LVDS 1:2<b class='flag-5'>分配器</b>中文手冊(cè)

    PS2-88,PS2-88/NF功率分配器MCLI

    PS2-88,PS2-88/NF功率分配器MCLIPS2-88功率分配器是MCLI品牌推出的一款高性能射頻微波器件,屬于PS2系列2路功率分配器。PS2-88功率分配器是一款高性能的射
    發(fā)表于 03-20 09:31

    PS2-185/NF帶狀線(xiàn)2路電源分配器

    PS2-185/NF帶狀線(xiàn)2路電源分配器PS2-185/NF帶狀線(xiàn)2路電源分配器具備高可靠性,通過(guò)不同種類(lèi)的結(jié)構(gòu)(如帶狀線(xiàn)、微帶和集總器件方式)來(lái)適合各種需求和應(yīng)用。主要特性電氣性能頻率范圍
    發(fā)表于 01-08 09:23

    英邁質(zhì)譜流路分配器:精準(zhǔn)控制,引領(lǐng)質(zhì)譜分析新高度

    在質(zhì)譜分析這一精密科學(xué)領(lǐng)域,流體的精準(zhǔn)輸送對(duì)于獲取高質(zhì)量數(shù)據(jù)至關(guān)重要。為了滿(mǎn)足這一嚴(yán)苛需求,Instrumax(英邁儀器)憑借其在流體控制領(lǐng)域的深厚積累,推出了全新的質(zhì)譜流路分配器。 這款質(zhì)譜流路
    的頭像 發(fā)表于 12-26 14:14 ?622次閱讀