lwip源码分析-内存管理模块

转载地址:http://capacity.blog.163.com/blog/static/208664131201252951117485/


lwip源码分析

Lwip,lightweight ip
协议,是一个轻量级的网络协议实现,前段时间基本上搞定了,写点东西,就当是对osi
模型的进一步了解吧。
我将以参照源码的方式由下向上解释lwip的工作原理,有什么错误欢迎指正。
首先将从lwip的内存机制说起,lwip提供了三种内存分配管理机制,一种是c
语言自带的内存机制,只要编译的时候将编译选项设置MEM_LIBC_MALLOC=1
就行,这个不多说。另外两种是Pool和Heap,字面意思就是内存池跟内存堆。
先说Heap
方式吧,这种方式先要在内存中分配一块大的连续的区域用作堆,来看一下它的数据结构
struct mem {
  /** index (-> ram[next]) of the next struct */
  mem_size_t next;
  /** index (-> ram[next]) of the next struct */
  mem_size_t prev;
  /** 1: this area is used; 0: this area is unused */
  u8_t used;
};
这就是内存非配的管理结构体。
#define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE) //12
// LWIP_MEM_ALIGN_SIZE是一个宏,用来实现编译器的字对齐,默认的是一字节对齐
#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)//1600

/*下面定义了堆的大小,翻译出来默认的大小大约是1612+2*sizeof(struct mem)*/
static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
/*指向ram_heap头地址,为了字节对齐,使用的是u8_t的指针 */
static u8_t *ram;
/*末尾的指针,总是不被使用的,用来作为一个结束判定标志 */
static struct mem *ram_end;
/*指向最低的没有被使用的内存地址,所以分配内存是从低地址向高地址分配的*/
static struct mem *lfree;
先来看这个堆管理方式内存的初始化函数,那些debug跟assert,还有sys
信号量语句就不要了
Void mem_init(void)
{
  struct mem *mem;
  ram = LWIP_MEM_ALIGN(ram_heap);//将堆的内存对齐
  /* 下面是初始化堆的头部,ram是全局变量*/
  mem = (struct mem *)ram;//这里头部的prev是空指针,next是MEM_SIZE_ALIGNED(
1600),这是因为第一次使用堆,因为没有分配区域,所以所有的在mem
以后的区域都可以作为这个结构体的数据区,在往后看就清楚了,这里可能说不明白
  mem->next = MEM_SIZE_ALIGNED;
  mem->prev = 0;
  mem->used = 0;
  /* 下面是初始化堆的尾部 */
  ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];//ram_end
指向堆的最后,直接设置used=0,next跟prev都是指向同一个位置,作为一个high-mark
使用。
  ram_end->used = 1;
  ram_end->next = MEM_SIZE_ALIGNED;
  ram_end->prev = MEM_SIZE_ALIGNED;
  /*下面初始lfree,就是指向ram */
  lfree = (struct mem *)ram;
}
初始化完了,就来看看怎么分配空间了,看一下下面的代码,里面很多的#if.. #endif,
还有assert,debug等都省略了,只挑核心的一部分
void  *mem_malloc(mem_size_t size)
{
  mem_size_t ptr, ptr2;
  struct mem *mem, *mem2;
  u8_t local_mem_free_count = 0;
  if (size == 0) {//如果size=0,啥都不用干
    return NULL;
  }
  size = LWIP_MEM_ALIGN_SIZE(size);//内存对齐
  if(size < MIN_SIZE_ALIGNED) {//分配的最小内存块必须大于MIN_SIZE_ALIGNED(12)
    size = MIN_SIZE_ALIGNED;
  }
  if (size > MEM_SIZE_ALIGNED) {//不能大于堆的大小(1600)
    return NULL;
  }
  do { 
    for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
         ptr = ((struct mem *)&ram[ptr])->next) //ptr取到偏移量
{
      mem = (struct mem *)&ram[ptr];  
      if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
//找到第一个满足要求的block
        if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + 
SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
          //并不是只要满足就分配,要检查是不是可以分割,即如果mem跟mem->next
之间的内存是不是大于size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED
,如果这样的话就要把这之间的内存分成两块,代码如下,还以比较易懂的,就是涉及到?
思父鲋刚肜嘈妥缓椭刚氲母摹?
          ptr2 = ptr + SIZEOF_STRUCT_MEM + size;//这里分配的内存包含了结构体
mem的大小
          mem2 = (struct mem *)&ram[ptr2];
          mem2->used = 0;
          mem2->next = mem->next;
          mem2->prev = ptr;
          mem->next = ptr2;
          mem->used = 1;
                  
          if (mem2->next != MEM_SIZE_ALIGNED) {
            ((struct mem *)&ram[mem2->next])->prev = ptr2;
          }
         } else {//内存不够分割,那就直接分配
          mem->used = 1;
        }//end  if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + 
SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) 

        if (mem == lfree) {//调整lfree指针
           while (lfree->used && lfree != ram_end) {
            lfree = (struct mem *)&ram[lfree->next];
          } 
}
       return (u8_t *)mem + SIZEOF_STRUCT_MEM;//注意这里返回的是mem + 
SIZEOF_STRUCT_MEM
,这就说明了当操作系统给我们分配内存的时候并不只是所申请的大小,实际要大几个字?
冢蛭郊右徊糠止芾斫峁固宓拇郏苁褂玫哪诖媸谴觤em + SIZEOF_STRUCT_MEM
开始的。
      }//end  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
         ptr = ((struct mem *)&ram[ptr])->next)
    }
  } while(local_mem_free_count != 0); //end do
  return NULL;//失败了,就返回NULL
}
既然知道怎么分配了那回收肯定就是分配的逆操作了,看一下这个函数,也是删去了不必?
膁ebug,assert等
Void mem_free(void *rmem)
{
  struct mem *mem;
  if (rmem == NULL) {
       return;
  }
  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
    return;
  }//上面的都是一个越界判断
  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
//直接就取到对应此块内存的结构体,
  mem->used = 0;
  if (mem < lfree) {
    lfree = mem;
  }
  plug_holes(mem);
}
下面来看一个plug_holes
这个函数,它的作用就是看看回收的内存能否跟前面的内存合并,就是消除空隙,这个跟?
诖婊厥蘸芟嗨?
static void plug_holes(struct mem *mem)
{
  struct mem *nmem;
  struct mem *pmem;

  nmem = (struct mem *)&ram[mem->next];//先看看跟后一块内存mem的next能不能合并
  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
    if (lfree == nmem) {能合并,修改lfree指针
      lfree = mem;
    }
    mem->next = nmem->next;/./能合并,修改next指针
    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;//能合并修改
prev指针,这里prev跟next都是偏移量,即相对于ram的偏移量
  }

  pmem = (struct mem *)&ram[mem->prev];
//再看看跟前一块内存块能不能合并,跟上面相似
  if (pmem != mem && pmem->used == 0) {
   
    if (lfree == mem) {
      lfree = pmem;
    }
    pmem->next = mem->next;
    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
  }、
到此回收内存就完成了。
还有realloc函数,alloc函数,都相似的说。先写这些,过几天再把Pool
类型的实现补充上来 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
INTRODUCTION lwIP is a small independent implementation of the TCP/IP protocol suite. The focus of the lwIP TCP/IP implementation is to reduce the RAM usage while still having a full scale TCP. This making lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM. lwIP was originally developed by Adam Dunkels at the Computer and Networks Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS) and is now developed and maintained by a worldwide network of developers. FEATURES * IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over multiple network interfaces * ICMP (Internet Control Message Protocol) for network maintenance and debugging * IGMP (Internet Group Management Protocol) for multicast traffic management * MLD (Multicast listener discovery for IPv6). Aims to be compliant with RFC 2710. No support for MLDv2 * ND (Neighbor discovery and stateless address autoconfiguration for IPv6). Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address autoconfiguration) * DHCP, AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection) and (stateless) DHCPv6 * UDP (User Datagram Protocol) including experimental UDP-lite extensions * TCP (Transmission Control Protocol) with congestion control, RTT estimation fast recovery/fast retransmit and sending SACKs * raw/native API for enhanced performance * Optional Berkeley-like socket API * TLS: optional layered TCP ("altcp") for nearly transparent TLS for any TCP-based protocol (ported to mbedTLS) (see changelog for more info) * PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet) * DNS (Domain name resolver incl. mDNS) * 6LoWPAN (via IEEE 802.15.4, BLE or ZEP) APPLICATIONS * HTTP server with SSI and CGI (HTTPS via altcp) * SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp * SNTP (Simple network time protocol) * NetBIOS name service responder * MDNS (Multicast DNS) responder * iPerf server implementation * MQTT client (TLS support via altcp) LICENSE lwIP is freely available under a BSD license. DEVELOPMENT lwIP has grown into an excellent TCP/IP stack for embedded devices, and developers using the stack often submit bug fixes, improvements, and additions to the stack to further increase its usefulness. Development of lwIP is hosted on Savannah, a central point for software development, maintenance and distribution. Everyone can help improve lwIP by use of Savannah's interface, Git and the mailing list. A core team of developers will commit changes to the Git source tree. The lwIP TCP/IP stack is maintained in the 'lwip' Git module and contributions (such as platform ports) are in the 'contrib' Git module. See doc/savannah.txt for details on Git server access for users and developers. The current Git trees are web-browsable: http://git.savannah.gnu.org/cgit/lwip.git http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git Submit patches and bugs via the lwIP project page: http://savannah.nongnu.org/projects/lwip/ Continuous integration builds (GCC, clang): https://travis-ci.org/lwip-tcpip/lwip DOCUMENTATION Self documentation of the source code is regularly extracted from the current Git sources and is available from this web page: http://www.nongnu.org/lwip/ Also, there are mailing lists you can subscribe at http://savannah.nongnu.org/mail/?group=lwip plus searchable archives: http://lists.nongnu.org/archive/html/lwip-users/ http://lists.nongnu.org/archive/html/lwip-devel/ There is a wiki about lwIP at http://lwip.wikia.com/wiki/LwIP_Wiki You might get questions answered there, but unfortunately, it is not as well maintained as it should be. lwIP was originally written by Adam Dunkels: http://dunkels.com/adam/ Reading Adam's papers, the files in docs/, browsing the source code documentation and browsing the mailing list archives is a good way to become familiar with the design of lwIP. Adam Dunkels Leon Woestenberg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值