上张图先:
该CPU L2=3MB
首先谈谈对象分配池.不管是内存池也好,对象池也好,首要的速度就是要快。可能有人说内存池为了碎片问题,那减轻碎片负担是不是也是为了速度快呢? 影响速度首先要从2个角度考虑,一个是机器的硬件特性,其次是缓存的命中率。硬件特性包括了对各种不同大小字段的读取,而缓存命中率在大内存的时候更显得犹为重要(因为内存没有硬盘的I/O瓶颈一说)。一会会结合数据图一一指出。所以在写的时候,为slub提供了以下特性:(多参考自linux源码,精练而成)
1.以页面为颗粒度,进行分配。
比如32机器上的页面为4KB,则每次分配以4KB做为颗粒度。当然这个可以调节,以支持大于一个页面的对象。
2.尽量从回收的页面中分配,以保持缓存命中率。并且维持这种顺序,不被分配打乱
比如一个页面分为100个对象,释放了10个对象,那么下次分配时,尽量从释放的10个中申请。而常见的链表式池,在使用次数多后,最影响的性能方面就是1号对象指向了最末尾等等
3.缓存的回收
虽然在服务器上内存的政策是鸵鸟式,这也是我以前的观点。但是现在的想法还是如果能做到一款动态伸缩,并且不影响效率,实在是快哉。不过在该代码里面,回收暂时不是重点,在回收的时候我也仅仅以vector遍历查找。一般不开
4.坏区的检测
对每个内存块分配特定的值,检测是否坏,或者不对的内存.可以屏蔽
5.多核的缓存支持
这里多核不是指多线程的支持。当然,它支持多线程并发。这里指的是利用多核建立的缓存结构。写之前对它将信将疑,不知道性能能提高多少,测试后也确实如此,性能提高得可怜。但也可能鉴于机器情况(双核),如果在忙碌的多核下,我相信性能还是有多提升的。
分析数据得出来的经验:
补充下测试环境,图里没写全:windows xp sp2+32位CPU
测试的时候, 网页等操作正常,myslub中所有检测全关
没有测试所有的数据,一是平常中已经测过,但没有记录,发上来总得象样点;二是心里大概有个样本了,没有花费太多时间做这事
我的测试方式:
S32 __CMYMalloc::Run()
{
DWORD t1 = GetTickCount();
while(g_bQuit==false && InterlockedDecrement(&m_nCount)+1 )
{
int i, nRand;
//申请
nRand = Random(0, name_viralloc::SUM_ALLOC_BYTE/m_nObjectSize-Vector.size());
for(i=0; i<nRand; ++i)
{
void *p = m_Kmem.KmemMalloc();
if(NULL==p)
{
break;
}
*(int*)p = 1000;
Vector.push_back(p);
++m_nMalloc;
}
//释放
nRand = Random(0, Vector.size());
for(i=0; i<nRand; ++i)
{
int j = Random(0, Vector.size());
if( NULL==Vector[j] )
{
continue;
}
m_Kmem.KmemFree(Vector[j]);
Vector.erase(Vector.begin()+j);
++m_nFree;
}
}
printf("spend:%d\n", GetTickCount()-t1);
return 0;
Vector,事先进行了reserve, name_viralloc::SUM_ALLOC_BYTE/m_nObjectSize计算出能分配的所有对象数。也就是说,一个单位的测试
动作包括了,随机分配内存,再计算出一个随机释放内存的数,并且对每个释放的索引再次随机。那么进行几次这样的单位测试成为一个很重要的指数。理想的值应该是跟能分配的所有对象数进行一个比例进行,我在测试中一般设为500-1000,并且以KB为单位。(如果是byte为单位,速度慢得重启,十几,二十分钟的计算)虽然有点偏颇,但还是可以做为一个样本参考。
总结出的一些内存经验:
单线程:
1.一次性分配2个页面做为一个单位颗粒,可以提高速度吗?证明不能,甚至还有拖慢的嫌疑。在32位机器下
2.在分配次数差不多的情况下,对象体积大的速度反而比小的快了很多。不得其解。后来和同事一致认为,就好比读取int i; char c,后者耗费的时间肯定比前者多一个指令
3.同样是2k的对象大小,在内存从32->128的情况下,系统的耗时差了10倍,我的差了4倍。进一步说明在大内存下,缓存不连续下的性能最大耗费
4.在128MB,我没有测试1k(太慢了)。但是我敢肯定跟32mb的差值远远小于2k的10倍。很简单原理如下:在系统进行分配内存时,都会或多或少的加入一些字段进行校验或者记录信息。如果你的大小是2K,那么对齐后的大小必然是>2k,如果系统的页面颗粒不进行调整,就会造成极大的浪费。所以你的对象分配时在32机器上跟4KB的页面对齐有问题,就要小心了。
多线程下:
5.尝试了下开多核的缓存设置(实现见代码,很简单的技巧)。在单线程下,反而显得慢。这个道理很简单,单个线程的忙碌,切到另外个CPU非常偶然。比如10次的0号CPU,1次的1号CPU。切的缓存命中不大,反而还要0号再次反切。在多线程下虽然有提升,但是少得可怜。由于硬件条件,没有再进行4核,8核的测试。
两个额外的想法:
1.C的链表 VS STL
先来推一个论点:
STL中只是对链表对象的一个包装,因为对用户是透明的,所以给用户展示的还是原来的结构。那么就意味着,链表信息无法原来的结构体中取得,如果要进行增,删,改,则必须进行查询找到链表节点
假设有结构
struct page
{
list head; //如果是C,以linux下的链表使用方法为代表,直接将信息作为结构体的一个成员变量
};
接着将page串成链表
C中,list_add_tail(). C中是以数据结构和操作方法分开,典型的过程式写法
C++中,list<page*> List; List.push(); 类的思维写法,一个对象包括代码和数据
当我要进行删除的时候
void *p; //我的内存地址
pPage = virt_to_head_page(p); //反算出page
C中,list_del(pPage);//直接删除,因为本身就有结点信息
C++中,List.删除(pPage); //我的做法是,先find到itr,然后erase.如果是remove,好象是一个遍历
2. 执行序列的优化
int i = 40;
int j = 100;
i = 20;
j = i;
i = 30;
那么在执行j=i的时候,能不能探测到下一条语句是i,可以事先缓存住i的地址,然后就可以直接执行i=30这条语句.那么在INTEL CPU中使用的技术是乱序。但找了几天资料也没搞明白怎么防止不乱序(即j=i先于i=30执行)。这样的话就可以衍生到应用层对象处理上优化。比如有1,10, 2玩家发来指令,先放在指令池里(cpu架构也是这么干的)但是可知1,2号在同一个页上,于是就可以先处理1,2玩家的命令。
分享到:
相关推荐
- **局部缓存(per-CPU slab cache)**:为了进一步提高性能,Slub分配器还为每个CPU维护了一个局部缓存,其中包含了部分slab缓存。这样,在同一CPU上进行内存分配时,可以优先使用局部缓存中的对象,避免了锁的竞争...
3. **缓存填充**:如果缓存为空,SLUB会尝试从空闲页(页面分配器)获取新的物理页,然后将这些页面转换为slabs。 4. **对象初始化**:新分配的页面会被切分为多个对象,并将每个对象设置为已初始化状态,准备分配。...
SLUB分配器的设计理念是简单易懂,最小化指令成本,并且注重调试能力以及执行时间的友好性。SLUB相较于SLAB,取消了队列,简化了slab结构,并且提高了处理器缓存利用率,降低了锁的争用。SLUB的一个显著特点是其优秀...
GDB插件使开发针对SLUB分配器Linux内核漏洞更加容易。 它显示slab缓存的内容,并允许在分配/释放操作上设置断点。 安装 无需安装,只需键入source slabdbg.py就足以让您入门。 用法 Usage: slab list - Display ...
本文将基于“slaballocators.pdf”这一资料,深入探讨 slab 分配器的基本概念、不同类型的 slab 分配器(SLAB、SLOB 和 SLUB)以及它们的发展历程。 #### 二、Slab 分配器的角色 在 Linux 内核中,内存管理是非常...
内核的物理内存管理主要依赖于伙伴系统和slab/slob/slub分配器。伙伴系统是基础,它按照页来管理内存,用于分配和释放多页大小的内存块。伙伴系统将空闲内存块链接在一起,形成一个空闲链,当需要分配内存时,会找到...
在Linux系统中,内存管理包括了多种机制和数据结构,如slub内存分配器、页(frame)管理、缓存(kmem_cache)等。以下是对这些关键知识点的详细说明: 1. 常见结构体 - `struct kmem_cache`: 这个结构体是Linux内核中...
总结来说,Linux内核内存分配器是一个复杂而精细的系统,它通过内存池、位图、链表以及专门的分配器如Slab、Slub和Slob,确保了内核内存的高效、低碎片和安全分配。了解这些概念对于理解和优化Linux内核的性能至关...
此外,Slab管理器还支持多级缓存(slab、slub和slob),以适应不同的性能和资源需求。 总的来说,Slab内存缓冲区管理器是Linux内核内存管理的关键组成部分,它通过精细化的内存分配策略和对象复用,显著提升了内核...
首先,我们需要了解SLUB分配器的基本概念。SLUB是Linux内核中的一种高效内存分配器,用于管理内核空间中的动态内存分配。它预先分配相同尺寸的对象,存储在称为slab的内存块中。每个slab包含多个对象,且每个对象在...
SLAB、SLUB和SLOB都是缓存分配器,它们维护了一个内存池,其中包含预分配且已初始化的对象,以满足频繁创建和销毁小对象的需求。这些分配器可以高效地管理小块内存,避免了传统内存分配时的开销。 Linux内存管理的...
因此,内核内存分配器必须具备高度的健壮性,能够及时处理错误并确保系统稳定运行。 在Linux内核中,物理内存被组织成称为“页面”(Pages)的基本单位。页面大小是由特定架构定义的,常见的有4KB或8KB。这种划分...
内存管理的层次结构图展示了不同级别的内存分配策略,如kmalloc处理小内存分配,slab分配器在内核层面提供缓存对象的分配,而vmalloc则用于大内存的非连续分配。`do_page_fault`函数是处理缺页异常的关键,当进程...
slab分配器在Linux 2.4.22之后被引入,优化了小对象的内存分配,而slub是2.6.22版本引入的slab分配器的简化版本。同时,页表管理和TLB刷新也是内存管理的重要环节,确保了虚拟地址到物理地址的正确映射。 总的来说...
SLAB 分配器将大块内存分割成小的、固定大小的对象缓存,每个缓存称为一个 slab。SLUB 是 SLAB 的简化版本,它省略了某些 SLAB 中的元数据,以减少内存开销和提高性能。 总的来说,Linux 内核通过 NUMA 架构、页表...
Linux内存管理的层次结构复杂,从页表管理到缺页异常处理,涉及多层调用,如do_page_fault处理缺页异常,通过kmem_cache_create和kmem_cache_alloc进行缓存分配,以及通过kmalloc、slab分配器等进行内存分配。...
此外,SLAB、SLUB和SLOB分配器进一步优化了内存分配,允许在一个页面内独立分配多个小块内存,有效减少了内部碎片。 内存管理层次关系图展示了从用户空间到内核空间的内存分配流程,包括kmalloc、slab分配器、页表...
因此,理解并使用更高效的内存分配器,如jemalloc或tcmalloc,可以显著提高内存分配效率。 缓存是提升性能的重要手段,Linux内核提供了多种缓存机制,如Page Cache、SLAB和SLUB等。理解这些缓存的工作原理,以及...
- 包括伙伴系统(buddy system)和slub/slab分配器,用于高效地分配和回收小块内存。 9. **高速缓存(Cache)**: - Linux内存管理中,缓存机制提高了I/O性能,如page cache和dentry cache等。 10. **内存泄漏...
- SLAB分配器被用于管理内核对象的内存分配,2.6内核引入了SLUB,这是一种更轻量级的版本,减少了元数据开销,提高了小对象分配的性能。SLUB允许更快的分配和回收,同时保持内存利用率的高效率。 3. **内存压缩** ...