linux高性能服务器--Ngix内存池简单实现

文章目录

      • 内存模型:
      • 流程图
      • 内存对齐
      • code

内存模型:

在这里插入图片描述

流程图

在这里插入图片描述

内存对齐

对齐计算
要分配一个以指定大小对齐的内存,可以使用如下公式:
假设要分配大小为n,对齐方式为x,那么 size=(n+(x-1)) & (~(x-1))。
举个例子:
n=17,x=4。即申请大小为17,对齐为4。则计算出对齐后的大小应该为
(17+4-1)&(~(4-1))=20;

code

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <fcntl.h>


#define MP_ALIGNMENT       		32
#define MP_PAGE_SIZE			4096
#define MP_MAX_ALLOC_FROM_POOL	(MP_PAGE_SIZE-1)

// 对齐
#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))

typedef struct mp_large_s {
	struct mp_large_s *next;
	void *alloc;

}mp_large_t;

typedef struct mp_node_s {
	unsigned char *last; // last之前为已使用的内存
	unsigned char *end; // last到end之间为可分配内存
	struct mp_node_s *next;
	size_t failed;
}mp_node_t;

typedef struct mp_pool_s {
	size_t max;

	mp_node_t* current;
	mp_large_t* large;

	mp_node_t head[0];

}mp_pool_t;


mp_pool_t *mp_create_pool(size_t size)
{
	mp_pool_t *p;
	// malloc无法分配超过4k的内存,size + sizeof(mp_pool_t) + sizeof(mp_node_s)保证有size大小可用
	int ret = posix_memalign((void*)&p, MP_ALIGNMENT, size + sizeof(mp_pool_t) + sizeof(mp_node_t));
	if (ret)
		return NULL;

	p->max = size;
	p->current = p->head;
	p->large = NULL;

	//(unsigned char*)(p + 1)
	// (unsigned char*)p + sizeof(mp_pool_t)
	p->head->last = (unsigned char*)p + sizeof(mp_pool_t)+sizeof(mp_node_t);
	p->head->end = p->head->last + size;
	p->head->failed = 0;

	return p;
}
void mp_destory_pool(mp_pool_t *pool) 
{
	mp_node_t *h, *n;
	mp_large_t *l;

	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			free(l->alloc);
		}
	}

	h = pool->head->next;

	while (h) {
		n = h->next;
		free(h);
		h = n;
	}

	free(pool);
}

void *mp_alloc_small(mp_pool_t *pool, size_t size)
{
	unsigned char *m;

	struct mp_node_s *h = pool->head;
	size_t psize = (size_t)(h->end - (unsigned char *)h);
	int ret = posix_memalign((void*)&m, MP_ALIGNMENT, psize);
	if (ret)
		return NULL;

	mp_node_t *p, *new_node, *current;

	new_node = (mp_node_t *)m;
	new_node->next = NULL;
	new_node->end = m + psize;
	new_node->failed = 0;
	m += sizeof(mp_node_t);
	m = mp_align_ptr(m, MP_ALIGNMENT);
	new_node->last += size;

	current = pool->current;
	for (p = current; p->next; p = p->next)
	{
		// 如存在多次分配失败,current不再指向此node
		if (p->failed++ > 4)
		{
			current = p->next;
		}
	}
	p->next = new_node;
	pool->current = current ? current : new_node;

	return m;
}


static void *mp_alloc_large(mp_pool_t *pool, size_t size) 
{
	void *p = NULL;
	int ret = posix_memalign((void*)&p, MP_ALIGNMENT, size);
	if (ret)
		return NULL;
	
	mp_large_t *large;
	
	// 查找是否有已经释放的large,在large list里面找到一个 null的节点
	size_t n = 0;
	for (large = pool->large; large; large = large->next)
	{
		if (large->alloc == NULL)
		{
			large->alloc = p;
			return p;
		}
		// 避免遍历链条太长
		if (n++ > 3)
			break;
	}

	// 大内存块的头作为小块保存在small中
	large = mp_alloc_small(pool, sizeof(mp_large_t));

	// 头插法
	large->alloc = p;
	large->next = pool->large;
	pool->large = large;
}



void *mp_malloc(mp_pool_t *pool, size_t size)
{
	if (size > pool->max)
		return mp_alloc_large(pool, size);
	mp_node_t *p = pool->current;

	

	while (p)
	{
		
		if (p->end - p->last < size)
		{
			p = p->next;
			continue;
		}

		unsigned char *m = mp_align_ptr(p->last, MP_ALIGNMENT);
		p->last = m + size;
		return m;
	}
	
	return mp_alloc_small(pool, size);
}

void *mp_calloc(mp_pool_t *pool, size_t size) 
{

	void *p = mp_malloc(pool, size);
	if (p) {
		memset(p, 0, size);
	}

	return p;

}
void mp_free(mp_pool_t *pool, void *p)
{
	mp_large_t *l;
	for (l = pool->large; l; l = l->next)
	{
		if (p == l->alloc)
		{
			free(l->alloc);
			l->alloc = NULL;
			return;
		}
	}
}

void mp_reset_pool(mp_pool_t *pool) 
{

	mp_node_t *h;
	mp_large_t *l;

	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			free(l->alloc);
		}
	}

	pool->large = NULL;

	for (h = pool->head; h; h = h->next) {
		h->last = (unsigned char *)h + sizeof(mp_node_t);
	}

}

/******************* TEST *********************/
int main(int argc, char *argv[]) {

	int size = 1 << 12;

	mp_pool_t *p = mp_create_pool(size);

	int i = 0;
	for (i = 0; i < 10; i++) {

		void *mp = mp_malloc(p, 512);
		//		mp_free(mp);
	}

	printf("mp_align(123, 32): %d, mp_align(17, 32): %d\n", mp_align(24, 32), mp_align(17, 32));
	

	int j = 0;
	for (i = 0; i < 5; i++) {

		char *pp = mp_calloc(p, 32);
		for (j = 0; j < 32; j++) {
			if (pp[j]) {
				printf("calloc wrong\n");
			}
			printf("calloc success\n");
		}
	}

	//printf("mp_reset_pool\n");

	for (i = 0; i < 5; i++) {
		void *l = mp_malloc(p, 8192);
		mp_free(p, l);
	}

	mp_reset_pool(p);

	//printf("mp_destory_pool\n");
	for (i = 0; i < 58; i++) {
		mp_malloc(p, 256);
	}

	mp_destory_pool(p);

	return 0;

}

参考:
https://blog.csdn.net/Long_xu/article/details/126887578

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大模型系列】大模型的上下文长度解释与拓展

文章目录 1 什么是大模型的上下文长度&#xff1f;2 拓展大模型上下文长度的方式参考资料 1 什么是大模型的上下文长度&#xff1f; 大模型的上下文长度&#xff08;Context Length&#xff09;是指在自然语言处理&#xff08;NLP&#xff09;的大型语言模型&#xff08;Large…

自动的异地组网工具?

越来越多的企业和个人对远程访问和异地组网需求日益增加。为了满足这一需求&#xff0c;各种技术和服务也不断涌现。其中一项备受关注的技术就是自动的异地组网。本文将介绍这一技术的优势和特点。 【天联】组网的优势 天联组网技术以其卓越的性能和稳定性备受用户称赞。它的优…

数据结构:实验七:数据查找

一、 实验目的 &#xff08;1&#xff09;领会各种查找算法的过程和算法设计。 &#xff08;2&#xff09;掌握查找算法解决实际问题。 二、 实验要求 &#xff08;1&#xff09;编写一个程序exp8-1.cpp, 按提示输入10个任意的整形数据&#xff08;无序&#xff09;&…

数字旅游引领未来智慧之旅:科技应用深度重塑旅游生态,智慧服务全面升级打造极致高品质旅游体验

随着信息技术的飞速发展&#xff0c;数字旅游作为旅游业与科技融合的新兴业态&#xff0c;正以其独特的魅力和优势&#xff0c;引领着旅游业迈向智慧之旅的新时代。数字旅游不仅通过科技应用重塑了旅游生态&#xff0c;更通过智慧服务为游客带来了高品质的旅游体验。本文将深入…

从键入网址到网页显示,期间发生了什么?

从键入网址到网页显示&#xff0c;期间发生了什么&#xff1f; 孤单小弟【HTTP】真实地址查询【DNS】指南帮手【协议栈】可靠传输【TCP】远程定位【IP】两点传输【MAC】出口【网卡】送别者【交换机】出境大门【路由器】互相扒皮【服务器与客户端】相关问答 不少小伙伴在面试过程…

浅谈Agent AI智能体的未来

Agent AI智能体的未来非常广阔和潜力巨大。随着技术的发展和应用场景的不断拓展&#xff0c;我们可以期待以下几个方面的发展&#xff1a; 更加智能化&#xff1a;Agent AI智能体将会变得越来越智能&#xff0c;具备更强大的学习、推理和决策能力。它们可以通过大数据和机器学习…

java序列化和反序列化基础学习

一、前言 前文分析了java的反序列化的DNSURL利用链&#xff0c;但是对于java反序列化的一些过程不是很了解&#xff0c;这篇主要记录下学习java反序列基础知识 二、原理 概念 1、什么是序列化和反序列化 &#xff08;1&#xff09;Java序列化是指把Java对象转换为字节序列…

【C++】一篇文章带你深入了解stack、queue 和 priority_queue

目录 一、stack的介绍和使用1.1 stack的介绍1.2 stack的使用1.2.1.1 [stack对象的构造](https://legacy.cplusplus.com/reference/stack/stack/stack/)1.2.1.2 stack对象的容量操作1.2.1.2.1 [empty()函数](https://legacy.cplusplus.com/reference/stack/stack/empty/)1.2.1.2…

周三多《管理学原理》第3版/考研真题/章节练习题

普通高等教育“十一五”国家级规划教材《管理学原理》&#xff08;第3版&#xff0c;周三多、陈传明、龙静编著&#xff0c;南京大学出版社&#xff09;是我国高校广泛采用的管理学权威教材之一&#xff0c;也被众多高校&#xff08;包括科研机构&#xff09;指定为考研考博专业…

UDP/TCP

udp/tcp特征 udp&#xff1a; 无连接不可靠传输面向数据包全双工 tcp&#xff1a; 有连接可靠传输面向字节流全双工 解释&#xff1a; 有连接/无连接&#xff1a;发送消息时&#xff0c;对方是否必须要在线 比如我们聊天程序&#xff0c;我们给对方发送消息&#xff0c;是不管现…

C++笔试练习笔记 【2】: 数字统计 BC153 两个数组的交集 NC313 点击消除 AB5

文章目录 数字统计分析题目代码部分 两个数组的交集题目分析代码部分 点击消除题目解析代码部分 数字统计 分析题目 这个题涉及到两个知识点&#xff0c;就是枚举和数字的拆分 那么我的思路是进行遍历&#xff0c;拆分数字判断二的个数&#xff0c;枚举进行计数 那么数字的拆分…

C++协程库封装

操作系统&#xff1a;ubuntu20.04LTS 头文件&#xff1a;<ucontext.h> 什么是协程 协程可以看作轻量级线程&#xff0c;相比于线程&#xff0c;协程的调度完全由用户控制。可以理解为程序员可以暂停执行或恢复执行的函数。将每个线程看作是一个子程序&#xff0c;或者…

java同步大量数据到本地数据库方法总结

最近在做一个需求&#xff0c;就是我需要对三方接口调用的数据存放到本地的数据库里的数据表里面。那么一开始我就是直接一条一条save&#xff0c;结果发现耗时非常严重&#xff0c;后面我就进行了改进。就是分批次去同步或者分批次去异步。 现在我直接贴出我写的代码&#xf…

《MySQL对数据库中表的结构的操作》

文章目录 一、建表二、查看表结构所有能查看到数据库&#xff0c;表的操作痕迹的本质都是服务器保存下来了这些操作记录。 三、修改表1.改表名字2.添加表记录3.添加表的更多字段4.修改表的字段5. 删除表的字段 总结 以下的数据库表的操作全是基于user_db这个数据库操作的&#…

maven聚合,继承等方式

需要install安装到本地仓库&#xff0c;或者私服&#xff0c;方可使用自己封装项目 编译&#xff0c;测试&#xff0c;打包&#xff0c;安装&#xff0c;发布 parent: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://mav…

Golang图片验证码的使用

一、背景 最近在使用到Golang进行原生开发&#xff0c;注册和登录页面都涉及到图片验证码的功能。找了下第三方库的一些实现&#xff0c;发现了这个库用得还是蛮多的。并且支持很多类型的验证方式&#xff0c;例如支持数字类型、字母类型、音频验证码、中文验证码等等。 项目地…

《MySQL是怎样运行的》读书笔记(二) 从一条记录说起-InnoDB记录结构

前言 到现在为止&#xff0c; MySQL 还是一个黑盒&#xff0c;只知道使用客户端发送请求并等待服务器返回结果 那么表中的数据到底存到了哪里?以什么格式存放的? MySQL 是以什么方式来访问的这些数据? 相应的知识储备我只知道MySQL 服务器上负责对表中数据的读取和写入工…

C语言:文件操作(下)

片头 嗨&#xff01;小伙伴们&#xff0c;在前2篇中&#xff0c;我们分别讲述了C语言&#xff1a;文件操作&#xff08;上&#xff09;和 C语言&#xff1a;文件操作&#xff08;中&#xff09;&#xff0c;今天我们将会学习文件操作&#xff08;下&#xff09;&#xff0c;准…

C语言异步编程

回调函数在异步编程中有着重要的作用&#xff0c;在接口编程应用广泛&#xff0c;实战中经常会注册一个回调函数来接收其他程序返回的数据&#xff0c;这样做的好处是调用者无需主动去获取被调用者的数据&#xff0c;仅仅需要回调&#xff0c;让被调用者去传送数据&#xff0c;…

VS code 同步odata服务

在做UI5得开发过程中&#xff0c;经常会出现odata需要更新 那么已经加载过得项目如何去跟新odata服务呢 可以通过如下步骤 1.右键打开应用信息 2.找到manage service models 3.点击编辑 4.选中 刷新并保存