《LwIP协议栈源码详解——TCP/IP协议的实现》pbuf释放

姓名:朱小鹏   学号:16010130023

转载:http://blog.sina.com.cn/s/blog_62a85b950101am7f.html

【嵌牛导读】:昨天说到了数据缓冲pbuf的内存申请,今天继续来探究一下它的内存释放过程。

【嵌牛鼻子】:pbuf释放

【嵌牛提问】:LWIP中内存释放过程如何实现?

【嵌牛正文】:

不停的写东西,只是为了逃避某种心情。(PS:现在不停的C+V,只是迫于某人的鸭梨和对知识传播的追求,霍霍)

牢骚发完,Go On。昨天说到了数据缓冲pbuf的内存申请,今天继续来探究一下它的内存释放过程。由于pbuf的申请主要是通过内存堆分配和内存池分配来实现,所以,pbuf的释放也必须按照这两种情况分别讨论。

别慌,在展开讨论之前,还得说说某个pbuf能被释放的前提。在LWIP中这点很容易判断,因为前节说到pbuf的ref字段表示该pbuf被引用的次数,当pbuf被创建时,该字段的初始值为1,由此可判断,当pbuf的ref字段为1时,该pbuf才可以被删除,所以位于pbufs链表中间的pbuf结构是不会被删除成功的,因为他们的ref值至少是2。由此总之一下,能被删除的pbuf必然是某个pbufs链的首节点。当然pbuf的删除工作远不如此的简单,其中另一个需要特别注意的地方是,想想,很可能的情况是某个pbufs链的首节点删除成功后,该pbufs链的第二个节点就自然的成为该pbufs链的首节点,此时,该节点的ref值可能变为1(该节点没有被引用了),这种情况下,该节点也会被删除,因为LWIP认为它和第一个节点一起存储同一数据包。当第二个节点也被删除后,LWIP又会去看看第三个节点是否满足删除条件…就这样一直删一下去。当然,如果首节点删除后,第二个节点的ref值大于1,表示该节点还在其他地方被引用,不能再被删除,删除工作至此结束。这段话写的很口水,不如我们举个例子来看看这个删除过程。假如现在我们的pbufs链表有A,B,C三个pbuf结构连接起来,结构为A--->B--->C,利用pbuf_free(A)函数来删除pbuf结构,下面用ABC的几组不同ref值来看看删除结果:

(1)1->2->3函数执行后变为...1->3,节点BC仍在;

(2)3->3->3函数执行后变为2->3->3,节点ABC仍在;

(3)1->1->2函数执行后变为......1,节点C仍在;

(4)2->1->1函数执行后变为1->1->1,节点ABC仍在;

(5)1->1->1函数执行后变为.......,节点全部被删除。

如果您能说醍醐灌顶,那将是我最大的动力。

当可以删除某个pbuf结构时,LWIP首先检查这个pbuf是属于前节讲到的四个类型中的哪种,根据类型的不同,调用不同的内存释放函数进行删除。PBUF_POOL类型和PBUF_ROM类型、PBUF_REF类型需要通过memp_free()函数删除,PBUF_RAM类型需要通过mem_free()函数删除,原因不解释。

PBUF_RAM类型来自于内存堆,所以需通过mem_free()函数将pbuf释放回内存堆。这里,先得来看看内存堆的组织结构,见下图,在内存堆内部,内存堆管理模块通过在每一个内存分配块的顶部放置一个比较小的结构体来保存内存分配纪录(注意这个小小的结构体是内存管理模块自动附加上去的,独立于用户的申请大小)。这个结构体拥有三个成员变量,两个指针和一个标志,如图。next与prev分别指向内存的下一个和上一个分配块,used标志表示该内存块是否已被分配。图中需要注意的两个地方,first,图中每个内存块的大小是不同且可能随时变化的。Second,当系统初始化的时候,整个内存堆就是一个内存块,下图中是经过多次分配释放后内存堆呈现出来的结果。

内存堆管理模块根据所申请分配的大小来搜索所有未被使用的内存分配块,检索到的最先满足条件的内存块将分配给申请者,注意这里并不包括前面说到的那个小小结构体,所以用户得到的是used后的那个地址。当分配成功后,内存管理模块会马上在已经分配走了的数据区后面再插一个小小的结构体,并用next和prev指针将这个结构体串起来,以便于下次分配。经过几次的申请与释放,我们就看到了图中的内存堆组织模型。

当内存释放的时候,为了防止内存碎片的产生,上一个与下一个分配块的使用标志会被检查,如果他们中的任何一个还未被使用,这个内存块将被合并到一个更大的未使用内存块中。内存堆管理模块是这样做的,它根据用户提供的释放地址退后几个字节去寻找这个小小的结构体,利用这个结构体来实现内存堆得合并等操作。已经分配的内存块被回收后,使用标志used清零。当然,如果上一个与下一个分配块都已被使用,这时的释放就是最简单的情况,但这也是产生内存堆碎片问题的根源。

哎,要了老命了。

接着来讲其他三种结构通过memp_free()函数将pbuf释放回内存池的情况。前面的内容已经讲过了内存池POOL的结构,PBUF_POOL型pbuf主要使用的是MEMP_PBUF_POOL类型的POOL,PBUF_ROM和PBUF_REF型pbuf主要使用的是MEMP_PBUF型的POOL。这句话太绕了,你应该多读两遍。POOL结构的起始处有个next指针,用于指向同类型的下一个POOL,用于将同类型的POOL连接成一个单向链表,这里应该有必要仔细看看POOL池是怎样初始化的,代码很简单:

memp = LWIP_MEM_ALIGN(memp_memory);

for (i = 0; i < MEMP_MAX; ++i) {//对各种类型的POOL依次操作

memp_tab[i] = NULL;//空闲链表头初始为空

for (j = 0; j < memp_num[i]; ++j) {//把同类POOL链成链表

memp->next = memp_tab[i];

memp_tab[i] = memp;

memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);//取得下

}//一个POOL的地址

}

上面代码中有几个重要的全局变量,memp_memory是缓冲池的起始地址,前面已有所讨论;MEMP_MAX是POOL类型数; memp_tab用于指向某类POOL空闲链表的起始节点;memp_num表示各种类型POOL的个数;memp_sizes表示各种类型单个POOL的大小,对于MEMP_PBUF_POOL和MEMP_PBUF型的POOL,其大小是pbuf头和pbuf可装载数据大小的总和。

在这样的基础之上,POOL池的释放就简单了,首先根据POOL的类型找到相应空闲链表头memp_tab,将该POOL插在链表头上,并把memp_tab指向链表头,简单快捷。至于POOL池的的申请那自然而然的也就是对memp_tab头的操作了,这个相信你懂。

好了,到这里,LWIP的内存相关机制就基本介绍完毕。当然,它不可能这样简单,在以后使用到的地方,我会再加说明。

整理整理,收工。周末来啦….冬眠一天是必不可少的….哈哈

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容