linux 内存管理之红黑树 linux 内存管理
标签:二叉树linux分类: linux 内存
linux 内存管理之红黑树
谨以此文纪念过往的岁月。
我们可以将经常需要被读取的数据定义为 __read_mostly类型, 这样Linux内核被加载时,该数据将自动被存放到Cache中,以提高整个系统的执行效率
一.红黑树
1.1什么是红黑树
红黑树是满足一定特征的二叉树,其本质还是二叉树。
一般的,红黑树,满足以下性质,即只有满足以下全部性质的树,我们才称之为红黑树:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
其每一个红黑树的节点包括三个参数node_color,node_left,node_right。
http://blog.csdn.net/v_JULY_v/archive/2010/12/29/6105630.aspx 博文详细的讲述了红黑树的操作。
1.2linux中如何实现红黑树
1.2.1红黑树结构体
__attribute__((aligned(sizeof(long)))); --声明结构体long类型对齐。
红黑根节点描述
struct rb_root
{
struct rb_node *rb_node;
};
红黑树节点描述
struct rb_node
{
unsigned long rb_parent_color; --保存节点color同时保存父节点的指针值
#defineRB_RED0
#defineRB_BLACK1
struct rb_node *rb_right; --右子
struct rb_node *rb_left; --左子
}
设置父节点。
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
}
设置节点颜色
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
}
1.2.2红黑树的操作
红黑树的最主要特征在于其颜色满足特定的性质。普通的节点添加,极有可能破坏红黑树的性质,所以在添加红黑树节点时,需要将整个红黑树的颜色进行调整。
下面以rb_insert_color为例。
在理解下面的程序前要先理解两个函数,即红黑树的左旋和右旋。
左旋:
对照上图可以更好的理解下面的程序。将node设置为pivot,root不管。
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
{
struct rb_node *right = node->rb_right; --right = Y
struct rb_node *parent = rb_parent(node); --parent = P
if ((node->rb_right = right->rb_left)) --pivot的右子设置为P的左子即pivot->rb_right = b
rb_set_parent(right->rb_left, node); --同时将b->parent 设置为pivot
right->rb_left = node; --将pivot设置为Y的左子
rb_set_parent(right, parent); --设置Y的parent为P
if (parent)
{
if (node == parent->rb_left) --如果pivot为P的左子
parent->rb_left = right; --则P的右子设置为Y
else
parent->rb_right = right; --否则P的左子设置为Y
}
else
root->rb_node = right;
rb_set_parent(node, right); --设pivot的parent为Y
}
对于右旋参照左旋即可了,这两个旋转类似。
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
{
struct rb_node *left = node->rb_left;
struct rb_node *parent = rb_parent(node);
if ((node->rb_left = left->rb_right))
rb_set_parent(left->rb_right, node);
left->rb_right = node;
rb_set_parent(left, parent);
if (parent)
{
if (node == parent->rb_right)
parent->rb_right = left;
else
parent->rb_left = left;
}
else
root->rb_node = left;
rb_set_parent(node, left);
}
关于左旋和右旋都是为了保证平衡二叉树的性质不变,即是通过左旋和右旋来保证红黑二叉树的第五条性质满足。
红黑二叉树的添加跟普通的二叉树的添加类似。不过在添加节点后需要对节点的颜色进行调整,甚至对树的结构进行调整,来满足红黑树的性质。
在博文http://blog.csdn.net/zhongjiekangping/archive/2010/05/26/5624503.aspx中对红黑树插入的情况做了详细的描述。
将下面函数对比上三幅图即可。
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent; --一个为父节点,一个为祖父节点
while ((parent = rb_parent(node)) && rb_is_red(parent)) --从node获得父节点指针值,并判断父节点是否为红色
{
gparent = rb_parent(parent);
if (parent == gparent->rb_left)
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else {
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
}
rb_set_black(root->rb_node);
}
在理解红黑二叉树后,再来理解内存管理。在linux中虚拟内存的vma采用红黑树的结构来管理。这也是为什么要去理解红黑树的结构。
二.虚拟内存管理
在start_kernel中有一段关于vma的初始化
vmalloc_init -> __insert_vmap_area
将已有的vma添加入管理。
static void __insert_vmap_area(struct vmap_area *va)
{
struct rb_node **p = &vmap_area_root.rb_node;
struct rb_node *parent = NULL;
struct rb_node *tmp;
while (*p) { --查询适合的插入点
struct vmap_area *tmp;
parent = *p;
tmp = rb_entry(parent, struct vmap_area, rb_node);
if (va->va_start < tmp->va_end)
p = &(*p)->rb_left;
else if (va->va_end > tmp->va_start)
p = &(*p)->rb_right;
else
BUG();
}
rb_link_node(&va->rb_node, parent, p); --将节点插入
rb_insert_color(&va->rb_node, &vmap_area_root); --调整红黑二叉树。
tmp = rb_prev(&va->rb_node);
if (tmp) {
struct vmap_area *prev;
prev = rb_entry(tmp, struct vmap_area, rb_node);
list_add_rcu(&va->list, &prev->list);
} else
list_add_rcu(&va->list, &vmap_area_list);
}
上面是vmalloc_init。
更多阅读
红黑树vs最小堆 c 最小堆
不谈内存,从算法上来讲红黑树插入是最坏情况要比较2logN次(最高的高度)外加不超过两次旋转,最小堆最坏情况是logN次红黑树删除不需要比较只需要不超过3旋转,查找最小值需要遍历logN,如果删除最小值树调整一般很小最小堆查询顶节点是O(1),
跆拳道红黑带考试 跆拳道红黑袋
今天是我跆拳道红黑带考试。终于轮到我们红黑带考试了,我紧张极了。考试开始了,先考的是品势一至八章。所有的品势我都会,所以,我做的还挺好。然后是俯卧撑。我一共做了20个,累得我直喘气。但是我印象最深刻的是打木板和踢木板。先考的是
135战法之红杏出墙 135战法
135战法之红杏出墙形态特征:均线系统呈典型的空头排列,股价长期下跌并远离长期均线,这时13日均线由下降趋于走平,股价从下向上突破13日均线,并且在13日均线上企稳,我们把这根站在13日均线的的阳线称为“红杏出墙”。形成机理:股价的连续
零叶翻红万树霜——古诗词秋之意象五:秋霜
零叶翻红万树霜 ——古诗词秋之意象五:秋霜 川 雪秋霜自古以来就是诗人抒发情感的意象。《诗经·蒹葭》中有“蒹葭苍苍,白露为霜”的诗句,说的是当河边芦苇呈青灰色时,露水也因气温降低而转化为霜:蒹葭苍苍,白露为霜。所谓伊人,在水一
红黑李大霄 李大霄微博
红黑李大霄来源:上海证券报发布时间:2013年10月09日 05:29 作者:屈红燕李大霄股票研究人士,曾在东莞证券工作,担任多个职务,主持东莞证券研究发展中心工作多年。2009年初,李大霄开始在英大证券工作,这个拥有1号股东代码的分析师,见证了