一、内存缓存 内核使用kmalloc和kfree函数来分配和释放一个内存块,与用户空间libc库中的malloc和free函数类似,但kmalloc具有不同的分配标志来表示不同环境的分配内存的要求。
在内核子系统中,可能需要频繁地分配和回收一定大小的内存,内恶化提供了相关的函数来预先分配一块特殊的内存缓存,作为内存池以作分配之用。子系统的内存块分配和回收都对这个内存池中进行。
在内核网络子系统中维护有其专属内存缓存的有:
1.套接字缓冲区描述符:这个缓存是由net/core/sk_buff.c中的skb_init分配的,用于分配sk_buff缓冲区描述符,sk_buff在网络子系统中频繁分配和回收
2.邻居协议映射:每二个邻居协议都使用一个缓存区,以分配L3层到L2层地址映射的数据结构
3.路由表:路由代码使用两块缓存,用于定义路径的两个数据结构
内存缓存相关的内核函数:
kmem_cache_create:创建一个缓存
kmem_cache_destroy:销毁一个缓存
kmem_cache_alloc:分配一个内存块
kmem_cache_free:释放一个内存块
通常调用这两个函数进行封装,上层调用封装函数进行操作,进行一些必要的处理。如kfree_skb要求释放一个sk_buff时,只有当所有对该缓冲区的引用都释放,而且相关的子系统也把必要的清理工作都做完了后,才会去调用kmem_cache_free。
二、缓存和hash表
缓存查询函数一般有一个输入参数,指出在缓存没命中时,是否创建一个新的元素。对缓存的建立,一般采用hash表的机制,将相同hash值的元素放入同一个列表中,通常查询这个列表的时间远大于在hash表索引时间,所以良好的hash表是使元素均匀分配到hash桶中。
三、引用计数
为了数据共享的有效管理,引入了引用计数机制。当组件申请和释放这个数据结构时,只递增和递减该结构的引用计数。只有到这个数据结构的引用计数归零后,才真正从内存释放这个数据结构。所以,申请和释放操作必须成对出现。
四、垃圾收集
保证资源的可用性,必须保证回收使用完成的资源,通常有两种垃圾回收机制:
1.异步:启用一个定时器,定时扫描一组数据结构,将没有的数据结构释放掉;
2.同步:在资源不足时才触发垃圾回收机制,而不是靠定时器
五、函数指针和虚拟函数表(VFT)
函数指针是一种方便的方式,可以写出简洁的代码,又可以利用面向对象语言的某些优点。在数据机构的定义中,可以包含一组函数指针,该结构的某些或全部操作都可以通过嵌入的函数完成。如:
struct sock {
.......
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk, int bytes);
.......
}
可以根据不同的准则已经该对象所扮演的角色进行初始化,如调用sk_state_change时,实际可能会为不同的sock套接字而调用不同的函数。在网络子系统中函数指针的应用实例:
1.当入口数据封包或出口数据封包由路由子系统处理时,会对缓冲区数据结构中的两个函数做初始化
2.当数据封包准备好在网络硬件上传输时,就会交给net_device数据结构的hard_start_xmit函数指针,该函数由该设备所关联的设备驱动程序进行初始化
3.当L3协议想传输数据封包时,会调用一组函数指针中的一个,这些函数指针由该L3协议相关联的抵制解析协议负责初始化为一组函数,根据函数指针初始化的实际函数,可以产生透明化的L3层到L2层的地址解析。
阅读(282) | 评论(0) | 转发(0) |