Nginx学习笔记(五) 源码分析内存模块内存对齐

Nginx源码分析&内存模块

  今天总结了下C语言的内存分配问题,那么就看看Nginx的内存分配相关模型的具体实现。还有内存对齐的内容~~不懂的可以看看~~

src/os/unix/Ngx_alloc.h&Ngx_alloc.c

  先上源码:

/** Copyright (C) Igor Sysoev* Copyright (C) Nginx, Inc.*/#ifndef _NGX_ALLOC_H_INCLUDED_
#define _NGX_ALLOC_H_INCLUDED_#include <ngx_config.h>
#include <ngx_core.h>void *ngx_alloc(size_t size, ngx_log_t *log);
void *ngx_calloc(size_t size, ngx_log_t *log);#define ngx_free          free/** Linux has memalign() or posix_memalign()* Solaris has memalign()* FreeBSD 7.0 has posix_memalign(), besides, early version's malloc()* aligns allocations bigger than page size at the page boundary*/#if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN)void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log);#else#define ngx_memalign(alignment, size, log)  ngx_alloc(size, log)#endifextern ngx_uint_t  ngx_pagesize;
extern ngx_uint_t  ngx_pagesize_shift;
extern ngx_uint_t  ngx_cacheline_size;#endif /* _NGX_ALLOC_H_INCLUDED_ */
View Code

  这里部分代码是关于内存的申请的,是对Linux原有的内存申请函数的再一次封装。

  1.函数声明

void *ngx_alloc(size_t size, ngx_log_t *log);    //申请空间
void *ngx_calloc(size_t size, ngx_log_t *log);   //申请空间,并初始化为0

  2.源码解析

void * ngx_alloc(size_t size, ngx_log_t *log)
{void  *p;p = malloc(size);//malloc就是返回一个void*指针,指向分配的size大小的内存if (p == NULL) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,"malloc(%uz) failed", size);}ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);return p;
}void * ngx_calloc(size_t size, ngx_log_t *log)
{void  *p;p = ngx_alloc(size, log);//调用上面的函数if (p) {ngx_memzero(p, size);//并初始化为0,#define ngx_memzero(buf, n) (void) memset(buf, 0, n)
  }
return p;
}

  3.POSIX_MEMALIGN与MEMALIGN申请对齐内存,可以参考Linux man page:http://man7.org/linux/man-pages/man3/valloc.3.html

#if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN)void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log);#else#define ngx_memalign(alignment, size, log)  ngx_alloc(size, log)#endif
#if (NGX_HAVE_POSIX_MEMALIGN)
void * ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{void  *p;int    err;err = posix_memalign(&p, alignment, size);//stdlib.h 新接口if (err) {ngx_log_error(NGX_LOG_EMERG, log, err,"posix_memalign(%uz, %uz) failed", alignment, size);p = NULL;}ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,"posix_memalign: %p:%uz @%uz", p, size, alignment);return p;
}
#elif (NGX_HAVE_MEMALIGN)
void * ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{void  *p;p = memalign(alignment, size);//malloc.h 老接口if (p == NULL) {ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,"memalign(%uz, %uz) failed", alignment, size);}ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,"memalign: %p:%uz @%uz", p, size, alignment);return p;
}
#endif

数据对齐

概念:

  对齐跟数据在内存中的位置有关,为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”。 比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除。

功能:

  字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以有效地节省存储空间。

具体方法:

  指定对齐值:#pragma pack (value)时的指定对齐值value。

  取消对齐值:#pragma pach ()

具体分析:

struct A{char a;   //1int b;    //4short c;  //2
}struct B{int b;char a;short c;
}#pragma pack(1)
struct C{char a;int b;short c;
}
#pragma pack()#pragma pach(2)
struct D{char a;int b;short c;
}
#pragma pack()

  代码如上,想一想答案都是多少?

    sizeof(struct A)=10  //默认情况下,1字节的a在0x00000000,而整形b只能放在0x00000004(必须从4的整数倍开始)~0x00000007,最后的c在0x00000008~0x00000009

  sizeof(struct B)=8    //分析同上

  sizeof(struct C)=7    //这里指定了对齐值为1,那么a在0x00000000,b在0x00000001~0x0000004,c在0x00000005~0x00000006

  sizeof(struct D)=8    //分析同上

A、B、C、D的内存地址如图:

地址0x000000000x010x020x030040x050x060x070x080x09
Aa   bc
Bba c  
Cabc   
Da bc  

 src/core/Ngx_palloc.h&Ngx_palloc.cn内存池分析

  上源码:

/** Copyright (C) Igor Sysoev* Copyright (C) Nginx, Inc.*/#ifndef _NGX_PALLOC_H_INCLUDED_
#define _NGX_PALLOC_H_INCLUDED_#include <ngx_config.h>
#include <ngx_core.h>/** NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.* On Windows NT it decreases a number of locked pages in a kernel.*/
#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)#define NGX_DEFAULT_POOL_SIZE    (16 * 1024)#define NGX_POOL_ALIGNMENT       16
#define NGX_MIN_POOL_SIZE                                                     \ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),            \NGX_POOL_ALIGNMENT)typedef void (*ngx_pool_cleanup_pt)(void *data);typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;struct ngx_pool_cleanup_s {ngx_pool_cleanup_pt   handler;void                 *data;ngx_pool_cleanup_t   *next;
};typedef struct ngx_pool_large_s  ngx_pool_large_t;struct ngx_pool_large_s {ngx_pool_large_t     *next;void                 *alloc;
};typedef struct {u_char               *last;u_char               *end;ngx_pool_t           *next;ngx_uint_t            failed;
} ngx_pool_data_t;struct ngx_pool_s {ngx_pool_data_t       d;size_t                max;ngx_pool_t           *current;ngx_chain_t          *chain;ngx_pool_large_t     *large;ngx_pool_cleanup_t   *cleanup;ngx_log_t            *log;
};typedef struct {ngx_fd_t              fd;u_char               *name;ngx_log_t            *log;
} ngx_pool_cleanup_file_t;void *ngx_alloc(size_t size, ngx_log_t *log);
void *ngx_calloc(size_t size, ngx_log_t *log);ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);#endif /* _NGX_PALLOC_H_INCLUDED_ */
View Code

  1.#define NGX_DEFAULT_POOL_SIZE    (16 * 1024),表示NGX默认的内存池的大小为16*1024

  2.结构体ngx_pool_data_t内存数据块,ngx_pool_s内存池头部结构

 typedef struct {u_char      *last;  //当前内存池分配到此处,即下一次分配从此处开始u_char      *end;   //内存池结束位置ngx_pool_t  *next;  //内存池里面有很多块内存,这些内存块就是通过该指针连成链表的ngx_uint_t  failed; //内存池分配失败次数} ngx_pool_data_t;    //内存池的数据块位置信息struct ngx_pool_s{    //内存池头部结构ngx_pool_data_t     d;       //内存池的数据块size_t              max;     //内存池数据块的最大值ngx_pool_t         *current; //指向当前内存池ngx_chain_t        *chain;   //该指针挂接一个ngx_chain_t结构ngx_pool_large_t   *large;   //大块内存链表,即分配空间超过max的内存ngx_pool_cleanup_t *cleanup; //释放内存池的callbackngx_log_t          *log;     //日志信息
};

  3.创建和销毁内存池:

ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log)//创建内存池
{ngx_pool_t
*p;p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log); //申请对齐内存空间if (p == NULL) {return NULL;}p->d.last = (u_char *) p + sizeof(ngx_pool_t); //下一次分配的开始地址,sizeof(ngx_pool_t)为申请的P的大小p->d.end = (u_char *) p + size;             //内存池结束位置,size是申请空间的小小 p->d.next = NULL; //内存链表的指向下一内存块的指针为空p->d.failed = 0; //失败次数size = size - sizeof(ngx_pool_t); //p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;//内存池最大块           p->current = p; //当前指向的内存块p->chain = NULL;p->large = NULL;p->cleanup = NULL;p->log = log;return p; } 
//该函数将遍历内存池链表,所有释放内存,如果注册了clenup(也是一个链表结构)亦将遍历该cleanup链表结构依次调用clenuphandler清理。同时,还将遍历large链表,释放大块内存
void
ngx_destroy_pool(ngx_pool_t *pool)//删除全部内存池(链上的所有内存块) {ngx_pool_t *p, *n;ngx_pool_large_t *l;ngx_pool_cleanup_t *c;//根据注册的ngx_pool_cleanup_s 来逐个销毁内存for (c = pool->cleanup; c; c = c->next) {if (c->handler) {ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "run cleanup: %p", c);c->handler(c->data); }}//销毁大内存块for (l = pool->large; l; l = l->next) {ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);if (l->alloc) {ngx_free(l->alloc);}} #if (NGX_DEBUG)/** we could allocate the pool->log from this pool* so we cannot use this log while free()ing the pool*/for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,"free: %p, unused: %uz", p, p->d.end - p->d.last);if (n == NULL) {break;}} #endif
  //普通内存池
  for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {ngx_free(p);if (n == NULL) {break;}}

  4.重置内存池:

//该函数将释放所有large内存,并且将d->last指针重新指向ngx_pool_t结构之后数据区的开始位置,同刚创建后的位置相同。
void
ngx_reset_pool(ngx_pool_t *pool) {ngx_pool_t *p;ngx_pool_large_t *l;//删除大内存块for (l = pool->large; l; l = l->next) {if (l->alloc) {ngx_free(l->alloc);//专门用于释放大内存ngx_free()}}//大内存块置为空pool->large = NULL;//重新修改每个内存块的大小for (p = pool; p; p = p->d.next) {p->d.last = (u_char *) p + sizeof(ngx_pool_t);} }

  5.注册cleanup

//cleanup结构体
struct ngx_pool_cleanup_s {ngx_pool_cleanup_pt   handler;void                 *data;ngx_pool_cleanup_t   *next;
};//注册cleanup函数,为以后清除做准备
ngx_pool_cleanup_t * ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{ngx_pool_cleanup_t  *c;c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));//申请内存池if (c == NULL) {return NULL;}if (size) {c->data = ngx_palloc(p, size); //申请数据空间if (c->data == NULL) {return NULL;}} else {c->data = NULL;}c->handler = NULL;c->next = p->cleanup;p->cleanup = c;ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);return c;
}

   6.内存分配函数

void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);

  主要介绍一下ngx_palloc()这个函数:

void * ngx_palloc(ngx_pool_t *pool, size_t size)
{u_char      *m;ngx_pool_t  *p;if (size <= pool->max) {//max与待分配内存进行比较p = pool->current;//从当前位置开始遍历pool链表do {m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);if ((size_t) (p->d.end - m) >= size) {p->d.last = m + size;return m;                     //成功分配size大小的内存
            }p = p->d.next;} while (p);return ngx_palloc_block(pool, size);  //链表里没有能分配size大小内存的节点,则生成一个新的节点并在其中分配内存 
    }return ngx_palloc_large(pool, size);      //大于max值,则在large链表里分配内存
}

  其中的ngx_palloc_block()函数:

//该函数分配一块内存,并加入到内存池中
static
void * ngx_palloc_block(ngx_pool_t *pool, size_t size) {u_char *m;size_t psize;ngx_pool_t *p, *new, *current;psize = (size_t) (pool->d.end - (u_char *) pool); //计算内存池大小 m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log); //申请与原来相同的大小,这样的话内存池就是以2的指数幂增大if (m == NULL) {return NULL;}new = (ngx_pool_t *) m; //新的内存块new->d.end = m + psize;new->d.next = NULL;new->d.failed = 0;m += sizeof(ngx_pool_data_t);//让m指向该块内存ngx_pool_data_t结构体之后数据区起始位m = ngx_align_ptr(m, NGX_ALIGNMENT);new->d.last = m + size; //在数据区分配size大小的内存并设置last指针 current = pool->current; for (p = current; p->d.next; p = p->d.next) {if (p->d.failed++ > 4) { //失败4次以上移动current指针current = p->d.next;}}p->d.next = new; //将这次分配的内存块new加入该内存池 pool->current = current ? current : new;return m; }

参考

http://hi.baidu.com/langwan/item/fdd3bf4a4ef66aefa4c06629

http://blog.csdn.net/wallwind/article/details/7463979

http://blog.csdn.net/livelylittlefish/article/details/6586946

转载于:https://www.cnblogs.com/coder2012/p/3151346.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/547721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

reactor p java_Java反应式框架Reactor中的Mono和Flux

1. 前言最近写关于响应式编程的东西有点多&#xff0c;很多同学反映对Flux和Mono这两个Reactor中的概念有点懵逼。但是目前Java响应式编程中我们对这两个对象的接触又最多&#xff0c;诸如Spring WebFlux、RSocket、R2DBC。我开始也对这两个对象头疼&#xff0c;所以今天我们就…

Visual Studio 20xx试用版升级为正式版(WIN7同样有效)图解、附带序列号

Visual Studio 2005|2008 试用版升级为正式版&#xff08;WIN7同样有效&#xff09;。 目录 一、步骤图解 二、win7破解工具下载 三、序列号 一、步骤图解 1.控制面板 > 程序和功能 > Visual Studio 2005|2008 启动、修复程序。如图&#xff1a; 2.填写序列号&#xff0…

NHibernate使用之详细图解

本文档适合初级开发者或者是第一次接触NHibernate框架的朋友&#xff0c;其中NHibernate不是最新的版本&#xff0c;但是一个比较经典的版本 NHibernate 2.1.2&#xff0c;其中用红线标注的部分一定要仔细看&#xff0c;这些都是容易忽略和出错的地方&#xff0c;笔者在此给大家…

disabling directory browsing

2019独角兽企业重金招聘Python工程师标准>>> I have seen several recommendation to increase web application security by disabling directory browsing (for example pg 388 in IBM WebSphere Deployment and Advanced Configuration by Barcia, Hines, et al)…

水印生成器第2版[原图质量水印可自定义设置]

简介&#xff1a;水印生成器&#xff0c;原理很简单&#xff0c;一时在网上没有找到打水印的网站&#xff0c;自己便做了一个&#xff0c;效果如下图&#xff0c;可自定义字体大小、字体类型以及颜色。 开发环境&#xff1a;vs 2010 [net 3.5 WindowsForms应用程序] 本文带给…

服务发现与负载均衡traefik ingress

ingress就是从kubernetes集群外访问集群的入口&#xff0c;将用户的URL请求转发到不同的service上。Ingress相当于nginx、apache等负载均衡方向代理服务器&#xff0c;其中还包括规则定义&#xff0c;即URL的路由信息&#xff0c;路由信息得的刷新由 Ingress controller 提供 …

GentleNet使用之详细图解[语法使用增强版]

目录第一章 开发环境第二章 简介第三章 Gentle.Net-1.5.0 下载文件包介绍第四章 使用步骤第五章 源码下载 第一章、开发环境&#xff1a;Vs 2010 Sql 2005 GentleNet 1.5.0 【Web网站程序 .Net Framework 3.5】第二章、简介&#xff1a;Gentle.Net是一个开源的优秀O/R M…

NBear简介与使用图解

NBear简介与使用图解框架类型&#xff1a;ORM映射框架简介&#xff1a;NBear是一个基于.Net 2.0、C#2.0开放全部源代码的的软件开发框架类库。NBear的设计目标是尽最大努力减少开发人员的工作量&#xff0c;最大程度提升开发效率&#xff0c;同时兼顾性能及可伸缩性。Demo版本&…

搭建私有helm仓库及图形界面

搭建私有helm仓库及图形界面 本篇主要介绍私有 helm 仓库 Chartmuseum 及图形界面 Monocular UI /kubeapps 的搭建 helm chart 能够很好的封装和管理我们的 kubernetes 应用&#xff0c;可以实现中间件、数据库、公共组件等快速发布。 什么场景下我们需要构建一个私有的helm仓…

神啊,6小时30分钟,完成想要的所有Lync测试

神啊 !记住这个日子 !从未想到&#xff0c;6小时30分钟&#xff0c;能做出这么多东西&#xff1a;从&#xff1a;2013-06-28---20&#xff1a;00到2013-06-29-----2&#xff1a;30 (辛苦&#xff0c;也是值得&#xff0c;客户是上帝&#xff0c;公司也好&#xff0c;个人也罢&a…

SubSonic框架使用图解

简介&#xff1a;SubSonic框架是一个优秀的、开源的ORM映射框架&#xff0c;同时提供符合自身需要的代码生成器。 官方下载地址&#xff1a;http://www.subsonic.org/pages/download.jsp 明白了SubSonic是什么之后&#xff0c;下面一起来看SubSonic的使用吧。 开发版本&#…

用户代理de疑惑

2019独角兽企业重金招聘Python工程师标准>>> 在计算机科学中&#xff0c;用户代理&#xff08;英语&#xff1a;User Agent&#xff09;指的是代表使用者行为的软件&#xff08;软件代理程序&#xff09;所提供的对自己的一个标识符。例如&#xff0c;一个电子邮件阅…

问题“The connection to the server....:6443 was refused - did you specify the right host or port?”的处理!

问题“The connection to the server <master>:6443 was refused - did you specify the right host or port?”的处理&#xff01; 一、故障产生 在不关闭kubernets相关服务的情况下&#xff0c;对kubernets的master节点进行重启。&#xff08;模拟服务器的异常掉电&a…

iBatis for Net 代码生成器(CodeHelper)附下载地址(已经升级为V 1.1)

CodeHelper是一款可以自己定义模板和生成内容的代码生成器&#xff0c;目前只支持MsSql数据库&#xff0c;这款代码生成器的初衷也只是为了生成MyBatis.net框架的配置文件而写的一个轻量级的代码生成器。CodeHelper下载文件包介绍&#xff1a;Template\... 存放模板文件夹&…

在Access中执行SQL语句

Access在小型系统开发中等到了广泛使用。虽然Access提供了可视化的操作方法&#xff0c;但许多开发人员还是喜欢直接用SQL语句操作数据表。如何在Access中打开SQL视图&#xff0c;对于初次使用Access的程序员可得费点时间呢。 1、ACESS2007 &#xff08;1&#xff09;点击“创建…

K8S+Helm 安装 Jupyterhub

准备配置文件 生成随机数 openssl rand -hex 32 # 8fc2826e9ce6930ec26c9fd541c0620b448a947357edbdf9647516af16bbc798配置config.yaml如下&#xff0c;token是上一步生成 proxy:secretToken: "8fc2826e9ce6930ec26c9fd541c0620b448a947357edbdf9647516af16bbc798&quo…

iBatis for net 框架使用

简介&#xff1a;ibatis 一词来源于“internet”和“abatis”的组合&#xff0c;是一个由Clinton Begin在2001年发起的开放源代码项目&#xff0c;到后面发展的版本叫MyBatis但都是指的同一个东西。最初侧重于密码软件的开发&#xff0c;现在是一个基于Java的持久层框架&#x…

php 图片后缀,PHP如何实现图片无后缀

在偶然间网站开发&#xff0c;实现网页内容抓取的时候&#xff0c;发现有些图片居然没有后缀。然后怀着踽踽独行的心态&#xff0c;去尝试了下这个以前没有遇见过的“重大发现”&#xff1a;当完成测试后&#xff0c;发现其原理&#xff0c;也是真心简单&#xff0c;其实也就是…

Office Web Apps Server 2013与PDF(一)

好吧……这个消息有点旧&#xff0c;迟了将近4个月。 Office Web Apps是微软各大服务产品系列中的一个基础服务&#xff0c;可以为SharePoint 2013、Exchange 2013、Lync 2013提供企业内文档的在线预览和编辑功能&#xff1b;同时它也是一个基础的互联网服务&#xff0c;为诸如…

nifi 实现数据库到数据库之间数据同步

数据同步 界面如下&#xff1a; 具体流程&#xff1a; 1、使用ExecuteSQL连接mysql数据库&#xff0c;通过写sql查询所需要的数据 2、nifi默认查出来的数据为Avro格式&#xff0c;所以需要ConvertAvroToJSON把Avro格式转化为json格式的数据 3、使用ConvertJSONToSQL把json数据转…