内存池的实现与场景分析

news2024/11/26 8:26:20

内存管理库

  • jemalloc 内存管理,C 语言。
  • tcmalloc 内存管理,C++。
  • 在头文件中引入即可。

确定 block 的大小、不确定 block 的释放时间,如何设计内存池 ?

在这里插入图片描述

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

// gcc mem_pool_v1.c -o  mem_pool_v1

#define MEM_PAGE_SIZE		4096

typedef struct mempool_s {
    int block_size; // 每个 block 的大小
    int free_count; // 可分配的 block 的数量

    char *free_ptr; // 指向可分配的 block 的起始位置
    char *mem;      // 指向内存块的起始位置
} mempool_t;


int mp_init(mempool_t *m, int size) {

	if (!m) return -1;
	if (size < 16) size = 16;

	m->block_size = size;

	m->mem = (char *)malloc(MEM_PAGE_SIZE);
	if (!m->mem) return -1;
	m->free_ptr = m->mem;
	m->free_count = MEM_PAGE_SIZE / size;

	int i = 0;
	char *ptr = m->free_ptr;
	for (i = 0;i < m->free_count;i++) {
		*(char **)ptr = ptr + size;
		ptr += size;
	}
	*(char **)ptr = NULL;

	return 0;
}

void mp_dest(mempool_t *m) {
	if (!m || !m->mem) return ;
	
	free(m->mem);

}


void *mp_alloc(mempool_t *m) {

	if (!m || m->free_count == 0) return NULL;

	void *ptr = m->free_ptr;

	m->free_ptr = *(char **)ptr;
	m->free_count --;
	
	return ptr;
}


void mp_free(mempool_t *m, void *ptr) {

	*(char **)ptr = m->free_ptr;
	m->free_ptr = (char *)ptr;
	m->free_count ++;
}


int main() {

	mempool_t m;

	mp_init(&m, 32);

	void *p1 = mp_alloc(&m);
	printf("1: mp_alloc: %p\n", p1);

	void *p2 = mp_alloc(&m);
	printf("2: mp_alloc: %p\n", p2);

	void *p3 = mp_alloc(&m);
	printf("3: mp_alloc: %p\n", p3);

	void *p4 = mp_alloc(&m);
	printf("4: mp_alloc: %p\n", p4);

	mp_free(&m, p2);

	void *p5 = mp_alloc(&m);
	printf("5: mp_alloc: %p\n", p5);
	

	return 0;
}

不确定 block 的大小,确定 block 的释放时间,如何设计内存池 ?

在这里插入图片描述

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

#define MEM_PAGE_SIZE		4096


typedef struct mp_node_s {
	char *free_ptr;
	char *end;
	struct mp_node_s *next;
} mp_node_t;


typedef struct mp_pool_s {
	struct mp_node_s *first;   // 指向第一个节点
	struct mp_node_s *current; // 指向当前可用的节点
	int max; // page size
} mp_pool_t;


int mp_init(mp_pool_t *m, int size) {

	if (!m) return -1;

	void *addr = malloc(size); // 4096
	mp_node_t *node = (mp_node_t*)addr;
	
	node->free_ptr = (char*)addr + sizeof(mp_node_t);
	node->end = (char*)addr + size;
	node->next = NULL;

	m->first = node;
	m->current = node;
	m->max = size;

	return 0;

}


void mp_dest(mp_pool_t *m) {

	if (!m) return ;

	while (!m->first) {

		void *addr = m->first;
		mp_node_t *node = (mp_node_t*)addr;

		m->first = node->next;

		free(addr);
	}
	
	return ;
}

void *mp_alloc(mp_pool_t *m, int size) {   // size < (4096-sizeof(mp_node_t))

	void *addr = m->current;
	mp_node_t *node = (mp_node_t*)addr;

	do {
		if (size <= (node->end - node->free_ptr)) {  

			char *ptr = node->free_ptr;
			node->free_ptr += size;

			return ptr;
			
		}
		node = node->next;
		
	} while (node);

	// new node

	addr = malloc(m->max); // 4096
	node = (mp_node_t*)addr;

	node->free_ptr = (char*)addr + sizeof(mp_node_t);
	node->end = (char*)addr + m->max;

	// 头插法
	node->next = m->current;
	m->current = node;

	char *ptr = node->free_ptr;
	node->free_ptr += size;

	return ptr;

}


int main() {
	mp_pool_t m;

	mp_init(&m, MEM_PAGE_SIZE);

	void *p1 = mp_alloc(&m, 16);
	printf("1: mp_alloc: %p\n", p1);

	void *p2 = mp_alloc(&m, 32);
	printf("2: mp_alloc: %p\n", p2);

	void *p3 = mp_alloc(&m, 64);
	printf("3: mp_alloc: %p\n", p3);

	void *p4 = mp_alloc(&m, 128);
	printf("4: mp_alloc: %p\n", p4);

	void *p5 = mp_alloc(&m, 256);
	printf("5: mp_alloc: %p\n", p5);

	mp_dest(&m);

}

内存池的好处

  • 内存池是内存块的管理组件
  • 首先要分配整块内存, 然后为整块内存制定一些策略,如果内存不够,就再分配一块。
  • 避免了小块的内存分配,避免了频繁地向操作系统申请内存
  • 避免了长期运行出现的内存碎片

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

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

相关文章

Linux: 进程优先级

Linux: 进程优先级 一、进程优先级概念二、如何查看进程优先级三、如何修改进程的优先级&#xff08;PRL vs NI&#xff09;四、为何优先级PRL必须限定范围五、进程其他特性 一、进程优先级概念 优先级的本质就是排队&#xff0c;而排队则是资源不足所引起的。在计算机中&#…

Sublime 彻底解决中文乱码

1. 按ctrl&#xff0c;打开Console&#xff0c;输入如下代码&#xff1a; import urllib.request,os; pf Package Control.sublime-package; ipp sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHand…

LLM:函数调用(Function Calling)

1 函数调用 虽然大模型能解决很多问题&#xff0c;但大模型并不能知晓一切。比如&#xff0c;大模型不知道最新消息(GPT-3.5 的知识截至 2021年9月&#xff0c;GPT-4 是 2023 年12月)。另外&#xff0c;大模型没有“真逻辑”。它表现出的逻辑、推理&#xff0c;是训练文本的统计…

spring注解@EventListener实现监听原理

文章目录 EventListener使用方式EventListener实现原理1.引入时机2 初始化时机3 作用时机->将加了EventListener注解的方法识别出来&#xff0c;并封装为监听器&#xff0c;加载spring容器中 总结 EventListener使用方式 package com.cyl.listener;import org.springframew…

区间预测 | Matlab实现带有置信区间的GRNN广义回归神经网络时间序列未来趋势预测

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 Matlab实现带有置信区间的GRNN广义回归神经网络时间序列未来趋势预测 带有置信区间的GRNN(广义回归神经网络)时间序列未来趋势预测结合了广义回归神经网络(GRNN)的预测能力和置信区间的统计度量,以提供对未来…

Linux系统下NAT网卡出现问题,无法上网的解决办法

NTA连接无法上网&#xff0c;如果你试过网上所有教程&#xff0c;检测了Windows环境和Ubuntu环境没问题&#xff0c;且无法启动系统服务、ping网络失败、重置虚拟机网络配置器也无效等种种以下所列原因无法解决&#xff0c;可能在于没有获取IP地址&#xff0c;才不能上网 netw…

Taskflow:运行时交互(Interact with the Runtime)

Taskflow允许您通过将运行时对象作为任务的参数与调度运行时进行交互。这主要用于设计从Taskflow的现有设施扩展的专用并行算法。 创建Runtime对象 Taskflow允许静态任务和条件任务接受引用的tf::Runtime对象&#xff0c;该对象提供一组方法与调度运行时交互。以下示例创建一…

CleanMyMac X中文---让Mac焕发新生,Mac优化与清理的终极利器

CleanMyMac X是一款专为Mac用户设计的综合性系统优化工具。通过智能扫描&#xff0c;它能够快速识别并清理Mac磁盘上的垃圾文件、重复文件、无用语言安装包、iTunes缓存、邮件附件等&#xff0c;有效释放磁盘空间&#xff0c;提升Mac电脑的运行速度。此外&#xff0c;CleanMyMa…

灵途科技助力家电智能创新

从智能家电到个护健康&#xff0c;科技无时无刻不在刷新我们对智慧生活的认知&#xff0c;我们也从未像今天这样近距离贴近智慧生活的朴素本质——传感技术。灵途科技专注光电感知技术&#xff0c;持续为智能家电客户提供成熟的全方位感知解决方案。步入发展第八年&#xff0c;…

本地搭建多人协作ONLYOFFICE文档服务器并结合Cpolar内网穿透实现公网访问远程办公

文章目录 1. 安装Docker2. 本地安装部署ONLYOFFICE3. 安装cpolar内网穿透4. 固定OnlyOffice公网地址 本篇文章讲解如何使用Docker在本地服务器上安装ONLYOFFICE&#xff0c;并结合cpolar内网穿透实现公网访问。 Community Edition允许您在本地服务器上安装ONLYOFFICE文档&…

【OpenGL】(1) 环境搭建:运行简单的 OpenGL 教学示例程序

&#x1f4ad; 写在前面&#xff1a;我们尽可能地让大家以 最简单粗暴且无脑的方式&#xff0c;带大家配置好 OpenGL 环境&#xff0c;并跑出我们第一个示例程序。再次声明&#xff0c;本专栏所有教学都是基于 Windows上使用 VS2022 (X64) 的。本专栏主要内容是关于 3D 计算机图…

【讲解下Gitea】

&#x1f308;个人主页:程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

anaconda navigator updater 版本更新失败

打开后&#xff0c;更新界面持续很久 使用命令行查看版本 执行conda update anaconda-navigator 第一次执行中间失败&#xff0c;重新执行&#xff0c;更新成功

基于深度学习YOLOv8+PyQt5的水底海底垃圾生物探测器检测识别系统(源码+数据集+配置说明)

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;323海底 获取完整源码7000张数据集配置说明文件说明远程操作配置环境跑通程序 效果展示 基于深度学习YOLOv8PyQt5的水底海底垃圾生物探测器检测识别系统设计&#xff08;源码数据集配置文件&#xff09; 各文件说明 程序运…

网页布局案例 浮动

这里主要讲浮动 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>*{padding: 0;margin: 0;}.header{height: 40px;background-color: #333;}.nav{width: 1226px;heig…

【Java 多线程】从源码出发,剖析Threadlocal的数据结构

文章目录 exampleset(T value)createMap(t, value);set(ThreadLocal<?> key, Object value)ThreadLocalMap和Thread的关系 全貌 ThreadLocal是个很重要的多线程类&#xff0c;里面数据结构的设计很有意思&#xff0c;很巧妙。但是我们平时使用它的时候常常容易对它的使用…

学习【Redis高级篇】这一篇就够了

目录 1. 分布式缓存1-1. Redis持久化RDB持久化AOF持久化RDB与AOF对比总结 1-2. Redis主从集群全量同步增量同步主从优化总结 1-3. Redis哨兵哨兵作用集群监控原理集群故障恢复原理RedisTemplate访问哨兵总结 1-4. Redis分片集群散列插槽集群伸缩故障转移 2. 多级缓存2-1. 浏览器…

linux ubuntu 在保存文件不被允许,但是root权限

现象&#xff1a;MobaXterm_Personal_2登录到服务器&#xff0c;切换到root用户&#xff0c;然后使用MobaXterm_Personal_2自带的编辑器&#xff0c;编写文件&#xff0c;进行保存不被允许&#xff1b;查看目录root是有权限进行修改文件的&#xff0c;然后使用vim进行修改保存&…

【AcWing】蓝桥杯集训每日一题Day7|贡献法|4261.孤独的照片(C++)

4261.孤独的照片 AcWing 4261. 孤独的照片&#xff08;每日一题&#xff09; - AcWing难度&#xff1a;简单时/空限制&#xff1a;1s / 64MB总通过数&#xff1a;9889总尝试数&#xff1a;26088来源&#xff1a;USACO 2021 December Contest Bronze算法标签贡献法乘法原理 题目…

服务器安全事件应急响应排查方法

针对服务器操作系统的安全事件也非常多的。攻击方式主要是弱口令攻击、远程溢出攻击及其他应用漏洞攻击等。分析安全事件&#xff0c;找到入侵源&#xff0c;修复漏洞&#xff0c;总结经验&#xff0c;避免再次出现安全事件&#xff0c;以下是参考网络上文章&#xff0c;总结的…