日期:2014-05-17  浏览次数:20662 次

缓存的力量,windows下的slub分配器

上张图先:

该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.在分配次数差不多的情况下,对象体积大的速度反而比小的快了很多。不得其解。后来和同事一致认为,就好比读