oracle的freelist,关于Freelists和Freelist Groups[转]

1。如果表空间不指定segment_space_management auto,仍然会使用freelists和freelist groups来管理free block。

2。默认的freelists和freelist groups均为1。dump segment header block可以发现有一个freelists,称为mater free list,每个segment至少有一个master free list。如:

seg lst:: flg: used   lhd: 0x01c0000b ltl: 0x01c0000b

flg(flag)表示该freelist是否被使用

lhd(list header)表示位于该list中的第一个可用block的dba

ltl(list tail)表示位于该list中的最后一个可用block的dba,这个block必定位于hwm之下。

每个位于list中的block header中存在一个指针指向下一个可用的block,如:

fnx: 0x1c0008b

3。

如果创建segment时候指定多个freelists,比如设置freelists 2,那么在segment header

block中总共有3个free list,其中1个是main free list,另外2个是process free list。如:

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: used   lhd: 0x01c0008b ltl: 0x01c0008b

4。

只有当dml语句使block降到pctused参数指定值之下时,才会动态生成transaction free

list记录这些block的dba。而一个新分配的block则始终是位于process free list或者main free

list中的。每一个transaction都会动态创建自己的transaction free list,直到达到segment header

block size的限制。如:

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: used   lhd: 0x01c0008d ltl: 0x01c0008d

xct lst:: flg: used   lhd: 0x01c0008c ltl: 0x01c0008a xid: 0x0008.01f.000003d2

可以看到当删除数据使block重新可用的时候,位于freelist header处的是最后被分配的block,最先分配的block则处于freelist tail处。其中xid记录的是这次dml操作的transaction id。

问题:为什么最后被分配的block被放置在freelist header处?

5。

当重新insert数据或者发生row  migration的时候,会从transaction free list

header开始使用已经释放了的空闲block。如果transaction free list中没有 previously freed

blocks,那么就从process free list中寻找,因为可能定义了多个freelist,所以到底从哪个free

list中找,算法是(p % nfl) + 1,其中p表示dml操作进程的process id,nfl表示process free lists

number。如果在process free list中找不到或者根本就没有process free

list(segment只有一个freelist的情况),那么再从main free

list中找。仍然找不到的话,返回去再查transaction free

list,判断其中的transation是否已经commit,如果已经commit了,则把这个transaction free

list的flag标志为unused,同时把位于这个list中的所有block合并到main free list中。

问题:什么情况下transaction free list中的事务已经commit,但是却仍然没有previously freed blocks?

6。

所有的freelist中都没有找到可用的空闲块,此时segment就要开始分配新的extent,提升hwm。新分配的块被放置在main free

list中,如果有process free list存在,那么在使用前,根据数据请求量,每次最多转移5个block到相应的process

free list中,也就是在存在多个freelist的情况下,一次空间的请求总是读取transaction free

list或者process free list,而不会直接从main free list中读取。

从这个地方我们可以看到虽然多个

freelist可以缓解多个并发的session同时更新一个segment的需求,但是如果只有一个main free list,那么在从main

free list把block转移到process free list的这个环节上仍然会出现争用,此时就是多个freelist

group发挥效果的时候了。所以多个freelist

group不仅对于rac环境有效,对于单个instance也是可以缓解一定的资源争用的。但是无论是多个freelist还是多个freelist

group,都不可避免地会产生空间浪费的副作用,在某些特殊场合下甚至会让一个segment急速地增大。

7。对于freelist和

freelist group,tom在《effective oracle by

design》中有个比喻。想象有一台饮水机和源源不断的急需喝水的人们,一台饮水机就代表一个freelist,而一个想喝水的人就是一个准备向

segment中插入数据的会话。如果我们只有一个饮水机,那么所有想喝水的人都必须要排成一队,然后前一个喝完了下一个才能喝,这就产生了争用。设想一

下我们现在放置了10个饮水机,很明显人们可以排到10个队伍中的任何一个队伍里,毫无疑问效率大大加快了。这时瓶颈又出现了,就是如果一个饮水机里的水

被喝完了,就得给这个饮水机加水,此时如果只有一个加水员(这就是一个freelist

group),那么加水的速度可能就会跟不上了,添加freelist

group就是增加加水员,增加到2个,每个人负责5个饮水机,ok,效率又提升了。

对于空间浪费的负面影响,我们继续设想一下。来了一个十分能

喝水的人,他把住一个饮水机不停地喝,喝完了,引水员就加水,又喝完了,又加,即使是其它的9个饮水机里都是满满的水也没用,因为这个人一旦从某个饮水机

中开始喝水,除非到喝饱离开为止,他是绝对不会换到另外一个饮水机上去的(一个会话一旦从某个freelist中开始读取空闲块,就不会再使用其它的

freelist,即使其它的freelist表示还有很多的空闲块)。

8。设置了多个freelist

group,就会产生freelist blocks,这些block紧跟在segment header

block之后,假设我们设置了freelist groups 2,那么segment的第一个块是segment header

block,第2,3个块则都是freelist block。首先在segment header

block中存在1个freelist,称为super master free list或者segment master free

list。而在每个freelist block中又都存着1个master free list,还存在指定的process free

list,块的剩余空间则全部留给transaction free list使用。在单个instance中选择freelist

group的算法是(p % nfb) + 1 ,其中p表示dml操作进程的process id,nfb表示freelist groups

number。在rac环境中的算法则更加复杂,此处不作讨论了。

dump freelist block的一些输出如下:

frmt: 0x02 chkval: 0x0000 type: 0x16=data segment free list block with free block count

blocks in free list = 5 ccnt = 0

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

seg lst:: flg: used   lhd: 0x01c00116 ltl: 0x01c0011a

seg lst:: flg: unused lhd: 0x00000000 ltl: 0x00000000

结一下:如果我们定义了storage(freelists 4 freelist groups 2),那么在segment header

block中有1个super master free list,有2个freelist block,每个freelist

block中又有1个master free list和4个process free

list,当sml操作产生将本来不是free的block重新标志为空闲时,动态产生一个transaction free list。所有的free

list record中都只记录flag,list header block dba和list tail block

dba,整个freelist是由存在于每个位于列表中的block header中指向下一个free

block地址的指针这样类似链表的结构来完成的。

本文大部分知识来自:ixora和metalink

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22779291/viewspace-703841/,如需转载,请注明出处,否则将追究法律责任。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
freelist是一个用于管理内存的数据结构,它是一种空闲链表,用于存储已经被释放的内存块,以便下次使用时可以直接从freelist取出。 以下是一个简单的freelist实现方法: 1. 定义一个结构体来表示内存块,包含两个成员变量:指向下一个内存块的指针和内存块的大小。 2. 定义一个全局的指针变量,指向freelist的头部。 3. 当需要释放一块内存时,将其加入到freelist,即将该内存块的指针指向当前freelist的头部,并将freelist的头部指针指向该内存块。 4. 当需要分配一块内存时,从freelist取出一块内存,即将当前freelist的头部指针指向下一个内存块,并返回该内存块的指针。 5. 如果freelist没有足够的内存块,则向操作系统请求更多的内存。 以下是一个示例代码: ``` #include <stdlib.h> // 内存块结构体 struct block { struct block* next; // 指向下一个内存块 size_t size; // 内存块大小 }; // freelist头部指针 struct block* freelist = NULL; // 分配内存 void* allocate(size_t size) { // 检查freelist是否有足够的内存块 if (freelist == NULL || freelist->size < size) { // 向操作系统请求更多的内存 return malloc(size); } // 从freelist取出一块内存 struct block* block = freelist; freelist = freelist->next; return block + 1; } // 释放内存 void deallocate(void* ptr) { // 将内存块加入到freelist struct block* block = (struct block*)ptr - 1; block->next = freelist; freelist = block; } ``` 注意,这只是一个简单的freelist实现方法,实际应用可能需要进行优化和改进。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值