Nginx源码剖析之内存池和内存管理(6)

  注意每块大内存都对应有一个头部结构(next&alloc),这个头部结构是用来将所有大内存串成一个链表用的。这个头部结构不是直接向操作系统申请的,而是当做小块内存(头部结构没几个字节)直接在内存池里申请的。
这样的大块内存在使用完后,可能需要第一时间释放,节省内存空间,因此nginx提供了接口函数:

ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);

  此函数专门用来释放某个内存池上的某个大块内存,p就是大内存的地址。ngx_pfree只会释放大内存,不会释放其对应的头部结构,毕竟头部结构是当做小内存在内存池里申请的;遗留下来的头部结构会作下一次申请大内存之用。

3.4、cleanup资源

Nginx源码剖析之内存池和内存管理

  可以看到所有挂载在内存池上的资源将形成一个循环链表,一路走来,发现链表这种看似简单的数据结构却被频繁使用。由图可知,每个需要清理的资源都对应有一个头部结构,这个结构中有一个关键的字段handler,handler是一个函数指针,在挂载一个资源到内存池上的时候,同时也会注册一个清理资源的函数到这个handler上。即是说,内存池在清理cleanup的时候,就是调用这个handler来清理对应的资源。

  比如:我们可以将一个开打的文件描述符作为资源挂载到内存池上,同时提供一个关闭文件描述的函数注册到handler上,那么内存池在释放的时候,就会调用我们提供的关闭文件函数来处理文件描述符资源了。

3.5、内存的释放

  nginx只提供给了用户申请内存的接口,却没有释放内存的接口,那么nginx是如何完成内存释放的呢?总不能一直申请,用不释放啊。针对这个问题,nginx利用了web server应用的特殊场景来完成; 一个web server总是不停的接受connection和request,所以nginx就将内存池分了不同的等级,有进程级的内存池、connection级的内存池、request级的内存池。

  也就是说,创建好一个worker进程的时候,同时为这个worker进程创建一个内存池,待有新的连接到来后,就在worker进程的内存池上为该连接创建起一个内存池;连接上到来一个request后,又在连接的内存池上为request创建起一个内存池。

  这样,在request被处理完后,就会释放request的整个内存池,连接断开后,就会释放连接的内存池。因而,就保证了内存有分配也有释放。

  小结:通过内存的分配和释放可以看出,nginx只是将小块内存的申请聚集到一起申请,然后一起释放。避免了频繁申请小内存,降低内存碎片的产生等问题。

后记    

  今闲来无事,拿着个nginx源码在编译器上做源码剖析,鼓捣了一下午,至晚上不料中途停电,诸多部分未能保存。然不想白忙活,又花费了一个晚上,终至补全,方成上文,并修订至五日凌晨三点。同时,也参考和借鉴了dreamice、阿波等朋友们及yixiao等大牛的作品,异常感谢。读者若有兴趣,还可以看看sgi stl 的内存池及其管理(或者,日后自个也写下)。

  还是常有朋友问诸如下算法学习心得之类的,其实,我也是草包一个,不过,到底看来看来上次写的文章(由快速排序引申而来--如何学习算法)令读者不甚满意。学算法,先修心。当你养成了算法无惧的心理后,学习任何新的东西时,都将所向披靡。任何东西,扎扎实实学就够了。 至于工作,12.07日上班,在微博上给自己添加非常荣幸的给自己新添加了三条标签:推荐系统,机器学习,算法工程师。在学习决策树的过程中,发现网上并无好的资料可看,打算择日写一下。

  另外,对此前写的KMP算法做了总结,写了续集,读者可以参考之。 六之再续:KMP算法之总结篇:。相信,看过此文后,无论是谁,都一定可以把KMP算法搞懂了。

nginx for Linux v1.3.13 开发版下载

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/10920.html