内存池 - 原理分析(一)

简介: 内存池 - 原理分析(一)

这里写目录标题

思考

  1. 什么是内存池?内存池是做什么的?核心是什么?(心想这不是废话吗!肯定时管理内存的,具体呢)。
  1. 内存池这个所谓的“池子”怎么建造比较好?
  2. 内存池的使用场景?
  3. 有什么好的“轮子”使用?要不要自己“造轮子”?什么时候真的适合自己“造轮子”?如果造轮子,怎么造一个好用“轮子”?

充电站

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

什么是内存池

形象解释 :它的名字起的还是很贴切的,就像一个人叫“胖虎”,那他肯定是比较胖的,哈哈。起一个不太恰当的例子,一个所谓的“渣男”、“渣女”有一个“池塘”,更有甚者是“海洋”。有了这样的池塘以后就很方便,需要了就直接取用。比如“渣女”今天想吃水果了,心情不好需要安慰。 在“池塘”里捞一个“老实人”就很方便的达到目的。如果没有这样的池塘,自己又不想动,取寻找培养一个“老实人”是很花费时间的,达到目的后就冷落了,如果彻底断绝联系吧,万一以后还有有用的地方对吧?所以干脆放在自己的“鱼塘”。(这里只是举个例子,希望不要被喷啊)。 学术点解释 是在计算技术中经常使用的一种设计模式,其内涵在于:将程序中需要经常使用的核心资源先申请出来,放到一个池内,有程序自管理,这样可以提高资源的利用率,也可以保证本程序占有的资源数量。 内存池(Memory Pool) 是一种 动态内存分配 与管理技术,内存池则是在真正使用内存之前,先申请分配一大块内存(内存池)留作备用。当程序员申请内存时,从池中取出一块动态分配,当程序员释放时,将释放的内存放回到池内,再次申请,就可以从池里取出来使用,并尽量与周边的空闲内存块合并。

内存池作用

  内存池对一个空白的内存进行维护的过程,主要是对进行管理的。其核心是避免频繁的内存分配与释放。

  Linux下进程开始运行的时候,内存就 被划分出来了,这里面主要包括内核空间用户空间。用户空间主要能管理的就是mmap与堆,mmap有些进程没有,所以主要的还是对堆的管理。

客户端与服务器连接的中,当客户端send()数据给服务器,服务器在recv()之前需要有一块内存进行数据的存储。肯定会想到定义一个char buffer[],但时定义的buffer在栈区,随着函数的返回会被释放掉。这就需要在recv()之前malloc()出一个内存空间,给recv()去使用。这个过程可能还伴随着数据库的连接,recv()完以后进行业务处理。malloc()出来的内存存储的数据生命周期在整个连接过程中。

  在多个客户端进进行服务器连接的过程,必然会带来内存频繁的连接与释放。这样在申请和释放的过程造成利用率很低的一个主要原因就是内存碎片化。如果有未使用的存储器,但是这块存储器不能用来满足分配的请求,这时候就会产生内存碎片化问题。

综上所述:解决内存频繁分内,造成内存碎片化的方法就是内存池,再提一点,再工作当中,尽量是要用,不要自己造,但原理一定要明白

内存池的演变

版本一

最早的内存池雏形,malloc()申请一次内存,就用链表组织起来。将用到的内存加入uselist中,并且重载free()函数,设置flag。当释放内存是,用flag标记该内存未使用。当下次再需要内存是就在链表中找,再进行利用。

伪代码

// 伪代码
//节点结构体
struct memnode {
  void *addr;
  int size;
  int flag; //1 use, 0 free
  struct memonde *next;
}
//定义内存池
struct memnode *mempool;
//重载malloc()
void *nmalloc() {
  void *addr = malloc();
  struct memnode *node;
  ADD(mempool, node); //加入链表
}

版本二

  当然初始的内存池也存在较多的问题:会出现内存块越来越小的问题。

  提出按照不同的大小l来配固定大小的块。例如,假定最小的内存块为16Byte,可以进行32Byte、64Byte、128Byte、256Byte、512Byte、1024Byte。假设大于1024Byte为大内存块,交给系统进行分配和释放。其实先内存分配的过程中往往最难处理的就是这些小块内存块。这里引入小块大块的概念。

伪代码

// 伪代码
//节点结构体
struct memnode {
  void *addr;
  int size;
  int flag; //1 use, 0 free
  struct memonde *next;
}
//定义内存池
struct memnode *mempool;
//重载malloc()
void *nmalloc(int size) {
  void * addr = search(usetable, size); //循环做
  if (addr = NULL) {
    void *addr = malloc(size);
    struct memnode *node;
    ADD(mempool, node); //加入链表
  } 
}
//重载free()
void nfree(void *addr) {
  struct memnode *node = search_from(addr);
  node->flag = 0;
}

版本二的方式仍然有一些问题,这里提出来。主要是查找速度慢,内存块不是连在一起的(无法合并成一个大块)会有间隙,后续我们会继续讨论。

总结

本文主要介绍了什么是内存池,内存池简单来说是一种动态内存分配与管理技术。其核心避免频繁的内存分配与释放,减少内存碎片。并举例在CS模型中的体现。并且介绍了内存池一个演变的过程,从最早的内存池雏形,到版本二较为实用的方式。

后续

后续还需继续对内存池进行分析,后续更精彩。






相关文章
|
14天前
|
缓存 Java 编译器
Go 中的内存布局和分配原理
Go 中的内存布局和分配原理
|
24天前
|
Java
jmap 查看jvm内存大小并进行dump文件内存分析
jmap 查看jvm内存大小并进行dump文件内存分析
28 3
|
26天前
|
监控 算法 Java
|
26天前
|
Arthas 监控 Java
JVM内存问题之使用gperftools分析JNI Memory泄漏的具体步骤是什么
JVM内存问题之使用gperftools分析JNI Memory泄漏的具体步骤是什么
|
5天前
|
搜索推荐 Java API
Electron V8排查问题之分析 node-memwatch 提供的堆内存差异信息来定位内存泄漏对象如何解决
Electron V8排查问题之分析 node-memwatch 提供的堆内存差异信息来定位内存泄漏对象如何解决
10 0
|
27天前
|
存储 算法 Linux
操作系统中的内存管理:从原理到实践
本文深入探讨了操作系统中至关重要的内存管理机制,揭示了从理论到实现的复杂过程。通过分析内存分配、虚拟内存以及分页和交换等概念,本篇文章旨在为读者提供对现代操作系统内存管理技术的全面理解。结合最新的技术动态和研究成果,文章不仅阐述了内存管理的基本原理,还讨论了其在实际操作系统中的应用和优化策略。
28 1
|
1月前
|
监控 算法 Java
压测分析Java内存和CPU暂用
7月更文挑战第7天
27 5
|
9天前
|
监控 Java
JAVA性能优化- IntelliJ插件:java内存分析工具(JProfiler)
JAVA性能优化- IntelliJ插件:java内存分析工具(JProfiler)
20 0
|
21天前
|
存储 缓存 Java
(一) 玩命死磕Java内存模型(JMM)与 Volatile关键字底层原理
文章的阐述思路为:先阐述`JVM`内存模型、硬件与`OS`(操作系统)内存区域架构、`Java`多线程原理以及`Java`内存模型`JMM`之间的关联关系后,再对`Java`内存模型进行进一步剖析,毕竟许多小伙伴很容易将`Java`内存模型(`JMM`)和`JVM`内存模型的概念相互混淆,本文的目的就是帮助各位彻底理解`JMM`内存模型。