lnux内核的malloc实现(Oracle的cache buffer影子)

本文原创为freas_1990,转载请标明出处:http://blog.csdn.net/freas_1990/article/details/12845059

本文介绍一下malloc的原理,对mm感兴趣(或者对Oracle internal实现感兴趣)的同学能在本文找到感兴趣的内容。

malloc主要由两个结构体做支撑。

struct bucket_desc { /* 16 bytes */
 void   *page;
 struct bucket_desc *next;
 void   *freeptr;
 unsigned short  refcnt;
 unsigned short  bucket_size;
};

这个结构体是一个bucket descriptor。所有的object会通过链表链接起来。

struct _bucket_dir {	/* 8 bytes */
	int			size;
	struct bucket_desc	*chain;
};

这是bucket的目录。

我画了两个图来描述一个page(页面;4k)如何被这两个结构体描述。

一个4k的页面被分配到若刚个16 bytes大小的bucket中

一个4k的页面被分配到若刚个32 bytes大小的bucket中

那么,这些数据结构是如何被初始化的呢?

首先,在内核代码里,硬编码了如下数据。

struct _bucket_dir bucket_dir[] = {
	{ 16,	(struct bucket_desc *) 0},
	{ 32,	(struct bucket_desc *) 0},
	{ 64,	(struct bucket_desc *) 0},
	{ 128,	(struct bucket_desc *) 0},
	{ 256,	(struct bucket_desc *) 0},
	{ 512,	(struct bucket_desc *) 0},
	{ 1024,	(struct bucket_desc *) 0},
	{ 2048, (struct bucket_desc *) 0},
	{ 4096, (struct bucket_desc *) 0},
	{ 0,    (struct bucket_desc *) 0}};   /* End of list marker */

定义了粒度从16起的次方增长。

我写了简化的伪代码来描述整个流程。

malloc的伪代码

	procedure:
		get the bucket_desc with object size(for example 16 bytes)
		if(search bucket_desc list for free space){
			return  bdesc->freeptr
		} else {
			if(init_bucket_desc){
				return  bdesc->freeptr
			} else {
				panic("init_bucket_desc error")
			}
		}
		init_bucket_desc:
			if(page = get_one_page){
				sepreated the page(4k) with dir->size
				link all the pieces
			} else {
				panic("get page error")
			}
	end procedure

free的伪代码

procedure:
		get the bucket_desc with object size(for example 16 bytes)
		if(search bucket_desc list for the related bucket_desc){
			erase bdesc->freeptr
			bdesc->refcnt--
			if(bdesc->refcnt == 0){
				if(whole page NULL){
					if(!free_page(bdesc->page)){
						panic("free_page error")
					}
				}
			}
		} else {
			panic("input pointer not right")
		}
end procedure

关于数据结构性能的思考:

这里的主要数据结构就是单向链表,查找的时间复杂为O(N),属于暴力查找。

用了10个元素的数组做分拆,当内存使用过大的时候,这个数据结构就不能承载了。

或许采用一个hash或者树形结构能解决问题。

不过,对于20年前的内存来说,完全能应付了:)

时间: 2024-08-05 15:09:53

lnux内核的malloc实现(Oracle的cache buffer影子)的相关文章

Oracle Library Cache深入解析

Oracle Library Cache深入解析 每一个进入库缓存的对象,在库缓存中都被按照本身内容分割成多块进行存贮.Oracle这样做的目的是为了更灵活的内存管理,因为在内存寻找大块连续的内存,总比寻找小块连续内存更慢一些.如果一个库缓存对象(如一条SQL语句的执行计划),它所占的内存被切割成4个小块,它们分别被存放在库缓存的各处,并且互不相连.为了将这4个小块组合起来,Oracle另外这个库缓存对象分配一小块内存,这块内存中存有其他4个小块内存的地址,并且,还有一些有关此库缓存对象的基本信

Oracle 学习之--Buffer Cache深入解析

Oracle 学习之--Buffer Cache深入解析 服务器进程和数据库缓冲区高速缓存: 当服务器需要块时,需要按系列步骤读取块: 1.首先,服务器使用散列函数检查是否可以从缓冲区高速缓存中获得所需要的块.如果找到缓冲区,则将它移动到LRU列表中远离LRU末尾的另一端.这是逻辑读取,因为没有发生实际的I/O.如果在缓冲区高速缓存中找不到缓冲区,则服务器进程(Server)必须从数据文件中读取.

Oracle RAC cache fusion原理測试

Oracle RAC cache fusion是RAC最核心的工作机制.他把全部实例的SGA虚拟成一个大的SGA区,每当不同的实例请求同样的数据块,这个数据块就须要在实例间进行传递. 那究竟什么时候传递呢? 假设RAC有4个节点,当中的一个节点运行了一条SQL是全表扫描一张表,这个时候这个节点把这张表的数据载入到缓存:     方式1 :其它的节点假设须要同样的数据块会取第一个节点的数据,那是须要的时候取. 方式2 :还是第一个节点推送.   实验设定: 1.清空4个节点的share pool和

Oracle RAC cache fusion原理测试

Oracle RAC cache fusion是RAC最核心的工作机制,他把所有实例的SGA虚拟成一个大的SGA区,每当不同的实例请求相同的数据块,这个数据块就需要在实例间进行传递.那到底什么时候传递呢?加上RAC有4个节点,其中的一个节点执行了一条SQL是全表扫描一张表,这个时候这个节点把这张表的数据加载到缓存:其他的节点如果需要相同的数据块会取第一个节点的数据,那是需要的时候去,还是第一个节点推送呢?   实验设定: 1.清空4个节点的share pool和databuffer,其实当清除第

Oracle学习之buffer cache

1.block.buffer的概念 简述段区块的概念,引出块的概念 buffer的概念2.buffer cache的意义 减少IO 物理IO:磁盘读 逻辑IO:内存读 构造cr块:以后讲 undo引出来:回滚未提交数据:构造cr块 只要未提交,就可以回滚 只要未提交,别的会话就看不见修改3.buffer cache的内存组织结构 CBC:cache buffer chain 根据block地址找block的时候,需要使用到CBC chain LRU:最近最少使用 LRU.MRU LRUW 4.D

【转】cache buffer chain 第一篇

文章转自:http://www.jydba.net/cache-buffer-chain/ buffer cache的管理有两个重要的数据结构: hash bucket和cache buffer chain 1. hash bucket和cache buffer chain 可以想象,如果所有的buffer cache中的所有buffer都通过同一个结构来进行管理,当需要确定某个 block在buffer中是否存在时,将需要遍历整个结构,性能会相当低下. 为了提高效率,oracle引入了buck

【转】Cache Buffer Chain 第二篇

文章转自:http://m.bianceng.cn/database/Oracle/201407/42884.htm 测试环境:版本11gR2 SQL> select * from v$version where rownum=1; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Releas

buffer cache —— buffer busy waits/read by other session

oracle提供非常精确.有效的row level lock机制,多个用户同时修改数据时,为了保护数据,以块为单位挂起锁的情况不会发生.但这不太正确.以块为单位的锁虽然不存在,但正因为oracle I/O以块为单位组成,所以块单位锁是必要的.假设row1.row2两个行位于同一个块内,两名用户(用户1.用户2)各自对row1.row2执行update,逻辑上两个被更新行之间不存在需要相互保护的数据.因为oracle提供row level lock机制,所以修改互相不用的行完全不成问题.但是若两个

Oracle Rac ——Cache Fusion

Cache Fusion (缓存融合) 实际意义上讲就是通过互连网络在集群各个节点内的SGA之间进行块传递,这样做的好处是避免多次将块写入磁盘,再重新读入到其他实例的缓存中.当一个块从磁盘读入RAC环境中的首个实例的sga中,该块会被赋予一个锁资源(区别于行级锁),以让其他实例知道该块正在被使用(或是读),当另一个实例请求该块的操作时,当前实例sga会传递一个块的副本给另一个实例(该块为最新,并未改变):如果内存中的块已经被改变,但改变尚未提交,会传递一个CR副本,并改变相应的锁资源的级别.从本