前言

那么这里博主先安利一些干货满满的专栏了!

这两个都是博主在学习Linux操作系统过程中的记录,希望对大家的学习有帮助!

操作系统Operating Syshttps://blog.csdn.net/yu_cblog/category_12165502.html?spm=1001.2014.3001.5482Linux Syshttps://blog.csdn.net/yu_cblog/category_11786077.html?spm=1001.2014.3001.5482这两个是博主学习数据结构的同时,手撕模拟STL标准模版库各种容器的专栏。

STL源码剖析https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html


什么是内存池

因此最近博主准备开始学习Google的tcmalloc技术了,其实它就是一个高并发的内存池,效率做到极致,因此在此之前,博主先稍微学习了一下内存池的基本技术和基本概念,为后面的高并发内存池项目做准备,今天先给大家带来这个简单的内存池实现技术的简单demo代码。

所以本博客的代码,这是内存池的demo代码,实际上的内存池,比这个要复杂的多!这里的代码只是供学习使用。tcmalloc技术才是学习内存池的目标。

什么是内存池?

内存池是一种用来管理计算机程序中内存分配和释放的技术。它类似于一个预先准备好的内存存储区域,程序可以从中获取内存块而不是频繁地向操作系统请求。这种方式更高效,因为内存块的分配和释放开销较小,并且可以避免碎片化。内存池提高了程序的性能和响应速度,特别适用于频繁创建和销毁对象的场景,如网络服务器和并发编程。C语言的malloc,本质就是一个内存池。

内存池的基本原理

为了更高效的处理向内存获取资源,向内存获取资源,向内存释放资源,内存池一般这么做:

博主为了大家好理解,说的比较通俗:

  • 内存池初始化的时候,直接向内存先要一大块资源。
  • 向内存池获取资源的时候,从刚才初始化获取的一大块内存中切出一部分交给上层使用。
  • 当进程向内存池释放资源的时候,不直接释放到系统中,而是首先把不用的空间,交给内存池,内存池内部维护一个单链表,把还回来的资源串起来。
  • 当大块内存用完的时候,再向系统索要新内存。
  • 当进程索取资源的时候,优先从链表中获取还回来的资源,如果链表中没有资源了,再向系统索要资源。

ObjectPool.hpp


#ifndef __OBJECT_POOL__
#define __OBJECT_POOL__ #include <iostream>
#include <vector>
// #include "../utils/Log.hpp" // 大家下载代码的时候可以暂时不要日志 #define __DEFAULT_KB__ 128 /*
其实这里直接使用malloc的,malloc其实自己就是C语言的一个内存池,
其实我们可以直接用系统调用,跳过malloc,这样测试现象更明显
调用SystemAlloc替换malloc即可
*/ inline static void *SystemAlloc(size_t kpage)
{
void *ptr = nullptr;
#ifdef _WIN32
*ptr = VirtualAlloc(0, kpage * (1 << 12), MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
#else
// linux下brk mmap等 #endif if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
#endif
} template <class T>
class ObjectPool
{
private:
char *__memory = nullptr; // char 方便切
size_t __remain_bytes = 0; // 大块内存在切的过程中剩余的字节数
void *__free_list = nullptr; // 还回来的时候形成的自由链表
public:
T *New()
{
T *obj = nullptr;
// 不够空间 首选是把还回来的内存块对象进行再次利用
if (__free_list)
{
// 头删
void *next = *((void **)__free_list);
obj = (T *)__free_list;
__free_list = next;
return obj;
}
if (__remain_bytes < sizeof(T))
{
// 空间不够了,要重新开一个空间
__remain_bytes = __DEFAULT_KB__ * 1024;
__memory = (char *)malloc(__remain_bytes);
if (__memory == nullptr)
{
throw std::bad_alloc();
// logMessage(ERROR, "ObjectPool::New() malloc error");
}
}
obj = (T *)__memory;
size_t obj_size = sizeof(T) < sizeof(void *) ? sizeof(void *) : sizeof(T); // 小于一个指针的大小就给一个指针的大小就行
__memory += obj_size;
__remain_bytes -= obj_size;
// 定位new,显示调用T的构造函数,让T初始化一下
new (obj) T;
return obj;
}
void Delete(T *obj)
{
// 这样写无论是第一次插入还是后面的插入,都可以
// 这样写无论是32位还是64位,都可以
obj->~T(); // 显示调用析构函数
*(void **)obj = __free_list;
__free_list = obj;
}
}; #endif

testPerf.hpp

用于测试这个简易内存池的性能


#include "ObjectPool.hpp" struct TreeNode
{
int _val;
TreeNode *_left;
TreeNode *_right;
TreeNode()
: _val(0), _left(nullptr), _right(nullptr)
{
}
};
void TestObjectPool()
{
// 申请释放的轮次
const size_t Rounds = 5;
// 每轮申请释放多少次
const size_t N = 10000000;
size_t begin1 = clock();
std::vector<TreeNode *> v1;
v1.reserve(N);
for (size_t j = 0; j < Rounds; ++j)
{
for (int i = 0; i < N; ++i)
{
v1.push_back(new TreeNode);
}
for (int i = 0; i < N; ++i)
{
delete v1[i];
}
v1.clear();
}
size_t end1 = clock();
ObjectPool<TreeNode> TNPool;
size_t begin2 = clock();
std::vector<TreeNode *> v2;
v2.reserve(N);
for (size_t j = 0; j < Rounds; ++j)
{
for (int i = 0; i < N; ++i)
{
v2.push_back(TNPool.New());
}
for (int i = 0; i < N; ++i)
{
TNPool.Delete(v2[i]);
}
v2.clear();
}
size_t end2 = clock();
std::cout << "new cost time:" << end1 - begin1 << std::endl;
std::cout << "object pool cost time:" << end2 - begin2 << std::endl;
}

test.cc

#include "testPerf.hpp"
int main()
{
TestObjectPool();
return 0;
}

测试结果

内存池是什么原理?|内存池简易模拟实现|为学习高并发内存池tcmalloc做准备的更多相关文章

  1. Java高并发 -- 线程池

    Java高并发 -- 线程池 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. ...

  2. 深入源码分析Java线程池的实现原理

    程序的运行,其本质上,是对系统资源(CPU.内存.磁盘.网络等等)的使用.如何高效的使用这些资源是我们编程优化演进的一个方向.今天说的线程池就是一种对CPU利用的优化手段. 通过学习线程池原理,明白所 ...

  3. jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一)

    jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一) 线程池介绍 在日常开发中经常会遇到需要使用其它线程将大量任务异步处理的场景(异步化以及提升系统的吞吐量),而在 ...

  4. Linux内存描述之高端内存--Linux内存管理(五)

    1. 内核空间和用户空间 过去,CPU的地址总线只有32位, 32的地址总线无论是从逻辑上还是从物理上都只能描述4G的地址空间(232=4Gbit),在物理上理论上最多拥有4G内存(除了IO地址空间, ...

  5. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  6. Linux内存描述之高端内存–Linux内存管理(五)

    服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...

  7. linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/17093307 上一篇微博留下了这几个函数,现在我们来分析它们         sanity_c ...

  8. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  9. Linux 内核高-低端内存设置代码跟踪(ARM构架)

    对于ARM中内核如何在启动的时候设置高低端内存的分界线(也是逻辑地址与虚拟地址分界线(虚拟地址)减去那个固定的偏移),这里我稍微引导下(内核分析使用Linux-3.0): 首先定位设置内核虚拟地址起始 ...

  10. Linux内核高端内存 转

        Linux内核地址映射模型x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图.   Linux内核地址空间划分 通 ...

随机推荐

  1. 【每日一题】12.Running Median (对顶堆)

    补题链接:Here 题意:动态的维护中位数的问题,依次读入一个整数,每当总个数为奇数时输出此时序列的中位数 使用对顶堆的在线做法. 为了实时找到中位数,我们可以建议两个二叉堆:一个小根堆.一个大根堆. ...

  2. 1 分钟在 Serverless 上部署现代化 Deno Web 应用

    作者 | 连喆人(掌上乾坤公司) 本文选自 "Serverless 函数计算征集令" 征文 利用 Serverless 的水平扩展与按量付费优势, 结合自定义运行时, 实现 Web ...

  3. 用线性二次模型建模大型数据中心,基于 MPC 进行冷却控制

    目录 一个总述 reviews 0 abstract 1 intro 2 related work 3 DC cooling(问题定义) 4 MPC(method) 4.1 Model structu ...

  4. navicat 查看,设计并导出数据库 ER图

    转载请注明出处: 1. navicat 查看 ER 图,有两种方式: 第一种:选中数据库,并右键点击选中逆向数据库到模型. 第二种:可以在工具栏点击查看,选中 ER,打开 某数据库,便会展示 该数据库 ...

  5. Ubuntu Linux下的PDF阅读器推荐——Okular

    安装方法 在Ubuntu下直接使用sudo apt-get install okular即可,如果中间遇到依赖项的问题,可以通过运行sudo apt --fix-broken install来自动修复 ...

  6. CSS - 怎么样在不同分辨率的情况下计算根元素需要的font-size的值

    一般我们做页面,肯定都会有设计图,移动端页面,一般情况下,UI出图都会定宽为640px,这也是移动端的标准尺寸:但是,我们也不能排除可能有其他特殊的情况可能需要做其他大小的设计图.所以,我们可以先定一 ...

  7. SQLServer数据库JDBC连接串参数的简单学习

    SQLServer数据库JDBC连接串参数的简单学习 背景 前段时间一直跟同事一起处理SQLServer 比其他数据库的deadlock更多的问题. 涉及到了几个驱动的参数. 想着问题基本上告一段落, ...

  8. [转帖]KVM调整磁盘大小

    https://www.jianshu.com/p/5ca598424eb9 一台win10的虚拟机磁盘空间不足了,需要调整磁盘的大小.上网搜索KVM调整磁盘大小,结果得出的博客都说只有raw格式的能 ...

  9. [转帖]使用 Grafana 监控 TiDB 的最佳实践

    https://docs.pingcap.com/zh/tidb/stable/grafana-monitor-best-practices 使用 TiUP 部署 TiDB 集群时,如果在拓扑配置中添 ...

  10. [转帖]金仓数据库KingbaseES分区表 -- 声明式创建分区表

    https://www.modb.pro/db/638045 1. 创建分区表同时创建分区 1.1 准备环境 # 创建分区表同时创建分区 create table tb1(id bigint,stat ...