Nginx源码分析 - 基础数据结构篇 - 内存池 ngx_palloc.c(02)

深入理解Nginx线程池【内附原理讲解以及源码分析】 本篇博客将从什么是并发编程、为什么要使用线程池、线程池的组成以及线程池的使用这4个方面对Nginx线程池进行刨析,相信耐心看完会对您有所帮助。 阅读详情
AI摘要

本文详细介绍了Nginx内存池的设计与实现,包括内存池的主要数据结构、内存分配与释放的具体函数,以及如何通过cleanup机制自定义清理内存数据。

目录

一、内存池

二、数据结构定义

1. ngx_pool_t 内存池主结构

2. ngx_pool_data_t 数据区域结构

3. ngx_pool_large_t 大数据块结构

4. ngx_pool_cleanup_t 自定义清理回调的数据结构

三、数据结构图

四、具体函数实现

1. 内存分配 ngx_alloc和ngx_calloc

2. 创建内存池ngx_create_pool

3. 销毁内存池ngx_destroy_pool

4. 重设内存池ngx_reset_pool

5. 使用内存池分配一块内存ngx_palloc和ngx_pnalloc

6. ngx_palloc_block,内存池扩容

7. 大内存块的释放ngx_pfree


Nginx的内存管理是通过内存池来实现的。Nginx的内存池的设计非常的精巧,很多场景下,我们可以将Nginx的内存池实现抽象出来改造成我们开发中的内存池。

一、内存池


一般我们使用malloc/alloc/free等函数来分配和释放内存。但是直接使用这些函数会有一些弊端:

  • 虽然系统自带的ptmalloc内存分配管理器,也有自己的内存优化管理方案(申请内存块以及将内存交还给系统都有自己的优化方案,具体可以研究一下ptmalloc的源码),但是直接使用malloc/alloc/free,仍然会导致内存分配的性能比较低。
  • 频繁使用这些函数分配和释放内存,会导致内存碎片,不容易让系统直接回收内存。典型的例子就是大并发频繁分配和回收内存,会导致进程的内存产生碎片,并且不会立马被系统回收。
  • 容易产生内存泄露。

使用内存池分配内存有几点好处:

  • 提升内存分配效率。不需要每次分配内存都执行malloc/alloc等函数。
  • 让内存的管理变得更加简单。内存的分配都会在一块大的内存上,回收的时候只需要回收大块内存就能将所有的内存回收,防止了内存管理混乱和内存泄露问题。

二、数据结构定义


1. ngx_pool_t 内存池主结构


/**
 * Nginx 内存池数据结构
 */
struct ngx_pool_s {
    ngx_pool_data_t       d; 		/* 内存池的数据区域*/
    size_t                max; 		/* 最大每次可分配内存 */
    ngx_pool_t           *current;  /* 指向当前的内存池指针地址。ngx_pool_t链表上最后一个缓存池结构*/
    ngx_chain_t          *chain;	/* 缓冲区链表 */
    ngx_pool_large_t     *large;    /* 存储大数据的链表 */
    ngx_pool_cleanup_t   *cleanup;  /* 可自定义回调函数,清除内存块分配的内存 */
    ngx_log_t            *log;      /* 日志 */
};

2. ngx_pool_data_t 数据区域结构


typedef struct {
    u_char               *last;  /* 内存池中未使用内存的开始节点地址 */
    u_char               *end;   /* 内存池的结束地址 */
    ngx_pool_t           *next;  /* 指向下一个内存池 */
    ngx_uint_t            failed;/* 失败次数 */
} ngx_pool_data_t;

3. ngx_pool_large_t 大数据块结构


struct ngx_pool_large_s {
    ngx_pool_large_t     *next;   /* 指向下一个存储地址 通过这个地址可以知道当前块长度 */
    void                 *alloc;  /* 数据块指针地址 */
};

4. ngx_pool_cleanup_t 自定义清理回调的数据结构


struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt   handler;  /* 清理的回调函数 */
    void                 *data; 	/* 指向存储的数据地址 */
    ngx_pool_cleanup_t   *next; 	/* 下一个ngx_pool_cleanup_t */
};

三、数据结构图


说明:

  • Nginx的内存池会放在ngx_pool_t的数据结构上(ngx_pool_data_t用于记录内存块block的可用地址空间和内存块尾部)。当初始化分配的内存块大小不能满足需求的时候,Nginx就会调用ngx_palloc_block函数来分配一个新的内存块,通过链表的形式连接起来。
  • 当申请的内存大于pool->max的值的时候,Nginx就会单独分配一块large的内存块,会放置在pool->large的链表结构上。
  • pool->cleanup的链表结构主要存放需要通过回调函数清理的内存数据。(例如文件描述符)

四、具体函数实现


1. 内存分配 ngx_alloc和ngx_calloc


ngx_alloc和ngx_calloc 主要封装了Nginx的内存分配函数malloc。

/**
 * 封装了malloc函数,并且添加了日志
 */
void *
ngx_alloc(size_t size, ngx_log_t *log)
{
    void  *p;
    //分配一块内存
    p = malloc(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;
}

/**
 * 调用ngx_alloc方法,如果分配成,则调用ngx_memzero方法,将内存块设置为0
 * #define ngx_memzero(buf, n)  (void) memset(buf, 0, n)
 */
void *
ngx_calloc(size_t size, ngx_log_t *log)
{
    void  *p;

    //调用内存分配函数
    p = ngx_alloc(size, log);

    if (p) {
    	//将内存块全部设置为0
        ngx_memzero(p, size);
    }

    return p;
}

2. 创建内存池ngx_create_pool


调用ngx_create_pool这个方法就可以创建一个内存池。

/**
 * 创建一个内存池
 */
ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log) {
	ngx_pool_t *p;

	/**
	 * 相当于分配一块内存 ngx_alloc(size, log)
	 */
	p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
	if (p == NULL) {
		return NULL;
	}

	/**
	 * Nginx会分配一块大内存,其中内存头部存放ngx_pool_t本身内存池的数据结构
	 * ngx_pool_data_t	p->d 存放内存池的数据部分(适合小于p->max的内存块存储)
	 * p->large 存放大内存块列表
	 * p->cleanup 存放可以被回调函数清理的内存块(该内存块不一定会在内存池上面分配)
	 */
	p->d.last = (u_char *) p + sizeof(ngx_pool_t); //内存开始地址,指向ngx_pool_t结构体之后数据取起始位置
	p->d.end = (u_char *) p + size; //内存结束地址
	p->d.next = NULL; //下一个ngx_pool_t 内存池地址
	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->d.next,并且只负责p->d的数据内容*/
	p->current = p;
	p->chain = NULL;
	p->large = NULL;
	p->cleanup = NULL;
	p->log = log;

	return p;
}

3. 销毁内存池ngx_destroy_pool


/**
 * 销毁内存池。
 */
void ngx_destroy_pool(ngx_pool_t *pool) {
	ngx_pool_t *p, *n;
	ngx_pool_large_t *l;
	ngx_pool_cleanup_t *c;

	/* 首先清理pool->cleanup链表 */
	for (c = pool->cleanup; c; c = c->next) {
		/* handler 为一个清理的回调函数 */
		if (c->handler) {
			ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
					"run cleanup: %p", c);
			c->handler(c->data);
		}
	}

	/* 清理pool->large链表(pool->large为单独的大数据内存块)  */
	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

	/* 对内存池的data数据区域进行释放 */
	for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
		ngx_free(p);

		if (n == NULL) {
			break;
		}
	}
}

4. 重设内存池ngx_reset_pool


/**
 * 重设内存池
 */
void ngx_reset_pool(ngx_pool_t *pool) {
	ngx_pool_t *p;
	ngx_pool_large_t *l;

	/* 清理pool->large链表(pool->large为单独的大数据内存块)  */
	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			ngx_free(l->alloc);
		}
	}

	pool->large = NULL;

	/* 循环重新设置内存池data区域的 p->d.last;data区域数据并不擦除*/
	for (p = pool; p; p = p->d.next) {
		p->d.last = (u_char *) p + sizeof(ngx_pool_t);
	}
}

5. 使用内存池分配一块内存ngx_palloc和ngx_pnalloc


/**
 * 内存池分配一块内存,返回void类型指针
 */
void *
ngx_palloc(ngx_pool_t *pool, size_t size) {
	u_char *m;
	ngx_pool_t *p;

	/* 判断每次分配的内存大小,如果超出pool->max的限制,则需要走大数据内存分配策略 */
	if (size <= pool->max) {

		p = pool->current;

		/*
		 * 循环读取缓存池链p->d.next的各个的ngx_pool_t节点,
		 * 如果剩余的空间可以容纳size,则返回指针地址
		 *
		 * 这边的循环,实际上最多只有4次,具体可以看ngx_palloc_block函数
		 * */
		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;
			}

			p = p->d.next;

		} while (p);

		/* 如果没有缓存池空间没有可以容纳大小为size的内存块,则需要重新申请一个缓存池pool节点 */
		return ngx_palloc_block(pool, size);
	}

	/* 走大数据分配策略 ,在pool->large链表上分配 */
	return ngx_palloc_large(pool, size);
}

/**
 * 内存池分配一块内存,返回void类型指针
 * 不考虑对齐情况
 */
void *
ngx_pnalloc(ngx_pool_t *pool, size_t size) {
	u_char *m;
	ngx_pool_t *p;

	/* 判断每次分配的内存大小,如果超出pool->max的限制,则需要走大数据内存分配策略 */
	if (size <= pool->max) {

		p = pool->current;

		/* 循环读取数据区域的各个ngx_pool_t缓存池链,如果剩余的空间可以容纳size,则返回指针地址*/
		do {
			m = p->d.last; //分配的内存块的地址

			if ((size_t)(p->d.end - m) >= size) {
				p->d.last = m + size;

				return m;
			}

			p = p->d.next;

		} while (p);

		/* 如果没有缓存池空间没有可以容纳大小为size的内存块,则需要重新申请一个缓存池*/
		return ngx_palloc_block(pool, size);
	}

	/* 走大数据分配策略 */
	return ngx_palloc_large(pool, size);
}

内存分配逻辑:

  • 分配一块内存,如果分配的内存size小于内存池的pool->max的限制,则属于小内存块分配,走小内存块分配逻辑;否则走大内存分配逻辑。
  • 小内存分配逻辑:循环读取pool->d上的内存块,是否有足够的空间容纳需要分配的size,如果可以容纳,则直接分配内存;否则内存池需要申请新的内存块,调用ngx_palloc_block。
  • 大内存分配逻辑:当分配的内存size大于内存池的pool->max的限制,则会直接调用ngx_palloc_large方法申请一块独立的内存块,并且将内存块挂载到pool->large的链表上进行统一管理。

6. ngx_palloc_block,内存池扩容


/**
 * 申请一个新的缓存池 ngx_pool_t
 * 新的缓存池会挂载在主缓存池的 数据区域 (pool->d->next)
 */
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);
	if (m == NULL) {
		return NULL;
	}

	new = (ngx_pool_t *) m;

	new->d.end = m + psize;
	new->d.next = NULL;
	new->d.failed = 0;

	/* 分配size大小的内存块,返回m指针地址 */
	m += sizeof(ngx_pool_data_t);
	m = ngx_align_ptr(m, NGX_ALIGNMENT);
	new->d.last = m + size;

	current = pool->current;

	/**
	 * 缓存池的pool数据结构会挂载子节点的ngx_pool_t数据结构
	 * 子节点的ngx_pool_t数据结构中只用到pool->d的结构,只保存数据
	 * 每添加一个子节点,p->d.failed就会+1,当添加超过4个子节点的时候,
	 * pool->current会指向到最新的子节点地址
	 *
	 * 这个逻辑主要是为了防止pool上的子节点过多,导致每次ngx_palloc循环pool->d.next链表
	 * 将pool->current设置成最新的子节点之后,每次最大循环4次,不会去遍历整个缓存池链表
	 */
	for (p = current; p->d.next; p = p->d.next) {
		if (p->d.failed++ > 4) {
			current = p->d.next;
		}
	}

	p->d.next = new;

	/* 最终这个还是没变 */
	pool->current = current ? current : new;

	return m;
}

分配一块大内存,挂载到pool->large链表上ngx_palloc_large:

/**
 * 当分配的内存块大小超出pool->max限制的时候,需要分配在pool->large上
 */
static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size) {
	void *p;
	ngx_uint_t n;
	ngx_pool_large_t *large;

	/* 分配一块新的大内存块 */
	p = ngx_alloc(size, pool->log);
	if (p == NULL) {
		return NULL;
	}

	n = 0;

	/* 去pool->large链表上查询是否有NULL的,只在链表上往下查询3次,主要判断大数据块是否有被释放的,如果没有则只能跳出*/
	for (large = pool->large; large; large = large->next) {
		if (large->alloc == NULL) {
			large->alloc = p;
			return p;
		}

		if (n++ > 3) {
			break;
		}
	}

	/* 分配一个ngx_pool_large_t 数据结构 */
	large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
	if (large == NULL) {
		ngx_free(p); //如果分配失败,删除内存块
		return NULL;
	}

	large->alloc = p;
	large->next = pool->large;
	pool->large = large;

	return p;
}

7. 大内存块的释放ngx_pfree


内存池释放需要走ngx_destroy_pool,独立大内存块的单独释放,可以走ngx_pfree方法。

/**
 * 大内存块释放  pool->large
 */
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p) {
	ngx_pool_large_t *l;

	/* 在pool->large链上循环搜索,并且只释放内容区域,不释放ngx_pool_large_t数据结构*/
	for (l = pool->large; l; l = l->next) {
		if (p == l->alloc) {
			ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
					"free: %p", l->alloc);
			ngx_free(l->alloc);
			l->alloc = NULL;

			return NGX_OK;
		}
	}

	return NGX_DECLINED;
}

cleanup机制 可以回调函数清理数据

Nginx的内存池cleanup机制,设计的非常巧妙。pool->cleanup本身是一个链表,每个ngx_pool_cleanup_t的数据结构上,保存着内存数据的本身cleanup->data和回调清理函数cleanup->handler。

通过cleanup的机制,我们就可以在内存池上保存例如文件句柄fd的资源。当我们调用ngx_destroy_pool方法销毁内存池的时候,首先会来清理pool->cleanup,并且都会执行c->handler(c->data)回调函数,用于清理资源。

Nginx的这个机制,最显著的就是让文件描述符和需要自定义清理的数据的管理变得更加简单。

分配一个cleanup结构:

/**
 * 分配一个可以用于回调函数清理内存块的内存
 * 内存块仍旧在p->d或p->large上
 *
 * ngx_pool_t中的cleanup字段管理着一个特殊的链表,该链表的每一项都记录着一个特殊的需要释放的资源。
 * 对于这个链表中每个节点所包含的资源如何去释放,是自说明的。这也就提供了非常大的灵活性。
 * 意味着,ngx_pool_t不仅仅可以管理内存,通过这个机制,也可以管理任何需要释放的资源,
 * 例如,关闭文件,或者删除文件等等的。下面我们看一下这个链表每个节点的类型
 *
 * 一般分两种情况:
 * 1. 文件描述符
 * 2. 外部自定义回调函数可以来清理内存
 */
ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size) {
	ngx_pool_cleanup_t *c;

	/* 分配一个ngx_pool_cleanup_t */
	c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
	if (c == NULL) {
		return NULL;
	}

	/* 如果size !=0 从pool->d或pool->large分配一个内存块 */
	if (size) {
		/*  */
		c->data = ngx_palloc(p, size);
		if (c->data == NULL) {
			return NULL;
		}

	} else {
		c->data = NULL;
	}

	/* handler为回调函数 */
	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;
}

手动清理 p->cleanup链表上的数据:(内存池销毁函数ngx_destroy_pool也会清理p->cleanup)

/**
 * 清除 p->cleanup链表上的内存块(主要是文件描述符)
 * 回调函数:ngx_pool_cleanup_file
 */
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd) {
	ngx_pool_cleanup_t *c;
	ngx_pool_cleanup_file_t *cf;

	for (c = p->cleanup; c; c = c->next) {
		if (c->handler == ngx_pool_cleanup_file) {

			cf = c->data;

			if (cf->fd == fd) {
				c->handler(cf); /* 调用回调函数 */
				c->handler = NULL;
				return;
			}
		}
	}
}

关闭文件的回调函数和删除文件的回调函数。这个是文件句柄通用的回调函数,可以放置在p->cleanup->handler上。

/**
 * 关闭文件回调函数
 * ngx_pool_run_cleanup_file方法执行的时候,用了此函数作为回调函数的,都会被清理
 */
void ngx_pool_cleanup_file(void *data) {
	ngx_pool_cleanup_file_t *c = data;

	ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
			c->fd);

	if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
		ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
				ngx_close_file_n " \"%s\" failed", c->name);
	}
}

 

/**
 * 删除文件回调函数
 */
void ngx_pool_delete_file(void *data) {
	ngx_pool_cleanup_file_t *c = data;

	ngx_err_t err;

	ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
			c->fd, c->name);

	if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
		err = ngx_errno;

		if (err != NGX_ENOENT) {
			ngx_log_error(NGX_LOG_CRIT, c->log, err,
					ngx_delete_file_n " \"%s\" failed", c->name);
		}
	}

	if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
		ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
				ngx_close_file_n " \"%s\" failed", c->name);
	}
}

 

StarRocks慢查询排查实战:从Query Plan到Profile的保姆级调优指南 本文提供StarRocks慢查询排查的实战指南,从Query Plan解析到Profile诊断,详细讲解如何识别执行计划中的危险信号和优化关键指标。通过物化视图优化、分布式执行调整和资源管控方案,帮助DBA快速定位并解决查询性能问题,提升数据库效率。 阅读详情

相关推荐

WPS专业版自带字体

WPS专业版其中一个好处就是自带了部分有版权的字体,就算你安装了没买授权,他也会给你在系统里面安装上这些字体,至于没授权继续用合不合规我不知道。但是带来的实实在在的好处就是有些子他支持的全啊。 /usr/share/fonts/wps-office/FZWBK.TTF: 方正魏碑_GBK,FZWeiBei\-S03:style=Regular /usr/share/fonts/wps-office/FZFSK.TTF: 方正仿宋_GBK,FZFangSong\-Z02:style=Regular /us

chenqioulin的博客 5698

Nginx源码分析(25篇)

Nginx源码分析 - 初探Nginx的架构 Nginx源码分析 - 基础数据结构篇 - 内存池 ngx_palloc.c Nginx源码分析 - 基础数据结构篇 - 数组结构 ngx_array.c Nginx源码分析 - 基础数据结构篇 - 缓冲区结构 ngx_buf.c Nginx源码分析 - 基础数据结构篇 - 双向链表结构 ngx_queue.c Nginx源码分析 ......

奇华资料的博客 9万+

5分钟搞懂SCMA:稀疏码多址接入的核心原理与实战应用

本文深入浅出地解析了SCMA(稀疏码多址接入)的核心原理与实战应用。通过对比传统正交多址技术,阐释了SCMA如何通过非正交叠加和稀疏码本设计,实现远超资源单元数的用户接入,从而有效应对5G海量机器通信(mMTC)的挑战。文章还探讨了其在上行海量连接、免授权接入等场景的应用潜力及工程实现中的关键考量。

zeta9的博客 264

浅谈Nginx源码

在剖析Nginx的网络事件模型之前,你需要对网络IO、Linux epoll有一定的了解,至于说为什么先拿这部分来分析,是因为Nginx的事件模型,是整个Nginx设计的核心,也是Nginx能够扛得住大量请求的关键,由内而外才能豁然开朗,大河奔流、终有源头。在modules目录中,是nginx event模块所支持的IO模型实现。在linux内核中,网络IO发展经过了以下几个阶段:阻塞IO、非阻塞IO、多路复用(select/poll/epoll)、异步IO(AIO)。

2503_91021863的博客 1303

Wireshark实战解析IEC 61850 GOOSE报文:智能变电站通信调试指南

网络协议分析是理解现代工业通信系统的基础,其核心原理在于对数据包的捕获、解码与解析。在电力自动化领域,IEC 61850标准定义了智能变电站内设备间高效、可靠的通信框架,其中GOOSE(通用面向对象变电站事件)协议因其基于以太网多播和快速重传机制,成为保护跳闸、联锁等关键信号传输的基石,其技术价值在于实现了微秒级延迟的高可靠性通信。掌握GOOSE报文的分析能力,对于现场调试、故障定位及系统验证至关重要。本文聚焦于使用Wireshark这一网络分析工具,深入解析GOOSE报文结构,涵盖从以太网帧头、协议标识到

weixin_34401479的博客 376

.ipynb文件深度解析:从JSON结构到Jupyter Notebook高效使用指南

在Python开发与数据处理领域,交互式编程正成为探索数据与验证思路的高效方式。Jupyter Notebook作为最流行的交互式环境之一,其默认文件格式.ipynb本质是一个基于JSON的文本文件,内部通过单元格组织代码、说明文字与运行结果。理解其JSON结构,不仅有助于掌握Notebook的存储原理,更能为文件损坏修复、版本控制与自动化转换提供基础。依托对单元格类型、魔法命令及输出可视化的熟练运用,数据分析和数据可视化流程可以变得更为流畅。同时,借助VS Code、nbconvert等工具,开发者能将.

weixin_28839629的博客 349

一文看懂Ngnix内存池源码 附带详细讲解,清晰结构图

可以先看一下大概过程: 首先Ngnix内存池分为主内存池和其他内存池,主内存用来管理其他内存池,和自身初始具有的能够分配的内存。 **但主内存池和其他内存池在结构定义上是一样的,**都是下面代码块中的 ,**且具有别名 ,**只不过其他内存池再被创建的时候,会被分割,将除去成员 以外的部分作为可分配内存。如下图所示,图中主内存池和其他内存池在大小上可能具有迷惑性,但实际上主内存池和其他内存池所占的大小是一样的,只不过可分配内存不一样。 这里是各结构体中的关系: 是一个分流函数,按一个标准分割大块内存分配

哇咔咔的博客 1113

五段式S型算法笔记

又因为有 v-v0= 0.5jt通式: 所以有 vm-v0= 0.5jtm 所以有4vm-4v0= 2jtm。算法1: v=2vm-v0-0.5*jt+2jt*tm-2jtm*tm。加加速度j 自己设置 已知,vmax自己设置已知;所以有4vm-4v0= 2jtm带入算法1。

qq_36658033的博客 681

02Nginx源码分析之总结内存开辟的相关函数(ngx_alloc.c,ngx_palloc.c)

02Nginx源码分析之总结内存开辟的相关函数(ngx_alloc.c,ngx_palloc.c) 前言: 写这一篇的目的是为了方便接下来的阅读,否则每次都要对应查找相应的函数,非常麻烦。 1 首先说ngx_alloc.c源文件中的开辟函数 1)ngx_alloc函数 /* * 功能:调用malloc开辟内存 */ void * ngx_alloc(size_t size, ngx_log_t *log) { void *p; p = malloc(size); if (p =

weixin_44517656的博客 598

Cube.js 安装避坑指南:从零到一键启动

本文是一份详细的Cube.js安装避坑指南,旨在帮助开发者从零开始顺利启动Cube.js。文章重点强调了安装前的环境准备,包括Node.js版本、包管理工具和项目路径等关键“地基”,并深入解析了使用npx安装的优势、数据库类型选择以及数据库连接配置的核心步骤与常见陷阱,确保您能高效完成安装并成功启动服务。

weixin_29218509的博客 429

1.Fay-UE5数字人工程导入(UE数字人系统教程)

ue5数字人系列教程(含源文件工程)

1万+

Nginx源码分析 - 基础数据结构篇 - 内存池 ngx_palloc.c

Nginx源码分析 - 基础数据结构篇 - 内存池 ngx_palloc.c 。 https://blog.csdn.net/initphp/article/details/50588790 Nginx的内存管理是通过内存池来实现的。Nginx的内存池的设计非常的精巧,很多场景下,我们可以将Nginx的内存池实现抽象出来改造成我们开发中的内存池。 内存池 一般我们使用malloc/a...

TuxedoLinux的博客 288

科研绘图系列:R语言绘制宏基因组分析的可视化图形(network & barplot & heatmap)

科研绘图系列:R语言多图形组合(network & barplot & heatmap)

专注生信领域 644

04Nginx源码分析之内存池(ngx_palloc.c)

02Nginx源码分析之内存池 前言: Nginx的内存管理是通过内存池来实现的。Nginx的内存池的设计非常的精巧,很多场景下,我们可以将Nginx的内存池实现抽象出来改造成我们开发中的内存池。 1 为何使用内存池 一般我们使用malloc/alloc/free等函数来分配和释放内存。但是直接使用这些函数会有一些弊端: 1)虽然系统自带的ptmalloc内存分配管理器,也有自己的内存优化管理方案(申请内存块以及将内存交还给系统都有自己的优化方案,具体可以研究一下ptmalloc的源码),但是直接使用mal

weixin_44517656的博客 477

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

nginx源码分析 nginx-1.11.1 参考书籍《深入理解nginx模块开发与架构解析》 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始化的过程中就首先初始化了ngx_cycle_t结构,无论是master或者worker进程都初始化了该结构,本文就会分析该结构中的相关作用与成员;本文也会对Nginx的内存管理进行相关的分析,Nginx的内存管...

qq_33339479的博客 614

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

探索Nginx:深入理解Nginx基础组件的使用

Nginx的每个进程内部都有一个自己的ngx_cycle。展开代码语言:C自动换行AI代码解释void *tag;*/ };

2509_93923299的博客 777

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

nginx内存池源码分析

1、简述 很多开源项目都有内存池,不过大多数开源项目的内存池设计都并不一样 nginx会为每一个连接创建内存池,连接断开就会释放内存池。 nginx内存池内存的分配区分大小快,代码如下 2、数据结构以及接口ngx_palloc.h: /* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #ifndef _NGX_PALLOC_H_INCLUDED_ #define _NGX_PALLOC_H_INCLUDED_ #inc

JesonYang的IT之路 1579

ngx_palloc.c函数分析

/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include #include static void *ngx_palloc_block(ngx_pool_t *pool, size_t size); static void *ngx_palloc_large(ngx_pool_t *pool, siz

Lce的专栏 1325

ngx_palloc_small

【代码】ngx_palloc_small。

weixin_41812346的博客 320

c++ 指针读取内存数据不行_Nginx源码分析 - 基础数据结构篇 - 内存池 ngx_palloc.c...

Nginx的内存管理是通过内存池来实现的。Nginx的内存池的设计非常的精巧,很多场景下,我们可以将Nginx的内存池实现抽象出来改造成我们开发中的内存池。内存池一般我们使用malloc/alloc/free等函数来分配和释放内存。但是直接使用这些函数会有一些弊端:1. 虽然系统自带的ptmalloc内存分配管理器,也有自己的内存优化管理方案(申请内存块以及将内存交还给系统都有自己的优化方案,具体...

weixin_39545269的博客 162

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_palloc_large 函数

声明在 src\core\ngx_palloc.c 中。定义在 src\core\ngx_palloc.c。

weixin_41812346的博客 500

【Linux网络编程】Nginx -- 内存池

【Linux网络编程】Nginx -- 内存池 参考致谢 本博客为博主的学习实践总结,并参考了众多博主的博文,在此表示感谢,博主若有不足之处,请批评指正。 【1】深入理解 Nginx 模块开发与架构解析 【2】理解 Nginx 源码 ...

CopperSun 技术博客 365

nginx源码分析--内存池

内存池是nginx很重要的数据结构,结构图大概如下。 ngx_palloc.h /* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #ifndef _NGX_PALLOC_H_INCLUDED_ #define _NGX_PALLOC_H_INCLUDED_ #include <ngx_config.h> #incl

标子 的专栏 805
上一篇: Nginx源码分析 - 初探Nginx的架构(01)
下一篇: Nginx源码分析 - 基础数据结构篇 - 数组结构 ngx_array.c(03)
老码农zhuli
老码农zhuli 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄14年 2456粉丝 312原创
评论 27
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值