前言

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

这两个都是博主在学习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. 分享10个高级sql写法

    本文主要介绍博主在以往开发过程中,对于不同业务所对应的 sql 写法进行归纳总结而来.进而分享给大家. 本文所讲述 sql 语法都是基于 MySql 8.0+ 博主github地址:http://gi ...

  2. jQuery组织后续事件 事件冒泡 事件委托 键被按下 批量操作 hover input 事件

    1. jQuery绑定事件的方式 1. $('').click(function(){}) 2. $('').on('click', function(){}) 2. 阻止后续事件执行 1. retu ...

  3. KVM 核心功能:磁盘虚拟化

    1 磁盘虚拟化简介 QEMU-KVM 提供磁盘虚拟化,从虚拟机角度看其自身拥有的磁盘即是实际的物理磁盘.实际上,虚拟机读写的磁盘数据保存在 host 上的物理磁盘.   QEMU-KVM 主要有如下几 ...

  4. 基于python开发的口罩供需平台

    基于python开发的口罩供需平台 预览地址:https://i.mypython.me 开发语言:python/django 意见反馈:net936艾特163.com

  5. java - 冒泡排序求最值

    public class Bubble3 { public static void main(String[] args) { int[] arr; arr = new int[]{2,3,6,1}; ...

  6. JS - HTML精确定位

    scrollHeight: 获取对象的滚动高度. scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最 ...

  7. [转帖]sql server 索引阐述系列六 碎片查看与解决方案

    https://www.cnblogs.com/MrHSR/p/9365720.html 一 . dm_db_index_physical_stats 重要字段说明 1.1 内部碎片:是avg_pag ...

  8. [转帖]Percolator 和 TiDB 事务算法

    https://cn.pingcap.com/blog/percolator-and-txn 本文先概括的讲一下 Google Percolator 的大致流程.Percolator 是 Google ...

  9. [转帖]sqlplus与shell互相传值的几种情况

    https://www.cnblogs.com/youngerger/p/9068888.html sqlplus与shell互相传值的几种情况 情况一:在shell中最简单的调用sqlplus $c ...

  10. 【转帖】ARM 虚拟化技术简介

    一. 虚拟化技术二. 虚拟化技术的比较2.1 全虚拟化和二进制重写(Pure virtualization and binary rewriting)2.2 半虚拟化( Para-virtualiza ...