内存池

内存池实现与分析

假装没事ソ 提交于 2019-12-03 21:16:43
内存池实现与分析 描述 程序中不可避免的因为需要动态分配内存,而大量使用堆上的内存。如果使用系统默认的函数new/delete或malloc/free来分配和释放堆上的内存,效率不高,同时还可能产生大量的内存碎片,导致长时间运行后性能愈发下降。为了提高性能,通常就需要考虑使用一些数据结构和算法来减少动态分配的发生,这也是内存池这个思想的来源。 在我们的服务器里,可以看到大量频繁申请和销魂内存的情况发生在接收处理网络数据的部分里,所以在这一部分的处理中我们就需要考虑使用内存池来优化性能。 算法思想 首先使用的方法是类似 SGI STL 中的 allocator 内存分配器的实现方式。设计了一个数组,负责管理内存页(MemPage)。每一个内存页都可分配连固定大小,范围在 8Bytes 到 64MBytes 之间的内存块。 内存块是在创建MemPage申请的一段连续大小的空间,同时另外用一个数组记录每个块所在的内存地址,分配的时候分配空闲的内存空间,释放的时候通过修改数组指向的位置达到释放的目的。 结构如下: 实现细节 首先定义的结构大小限制如下: #define _MIN_BLOCK_SIZE_ (8) //单内存块最小限制为8 Byte #define _MAX_BLOCK_SIZE_ (1 << 26 ) //单内存块最大限制为64 MByte #define _PAGE_MIN

垃圾回收机制

让人想犯罪 __ 提交于 2019-12-03 14:50:14
Python-垃圾回收(GC)机制 一、什么是GC 在Java中,对象所占用的内存在对象不再使用后会自动被回收。这些工作是由一个叫垃圾回收器 ( Garbage Collector )的进程完成的。 python和其他很多高级语言一样,都自带垃圾回收机制,即GC机制。 二、GC机制 Python中的垃圾回收是以引用计数为主,标记-清除和分代收集为辅。引用计数最大缺陷就是循环引用的问题,所以Python采用了辅助方法。 注意:   1、垃圾回收时,Python不能进行其它的任务,频繁的垃圾回收将大大降低Python的工作效率;   2、Python只会在特定条件下,自动启动垃圾回收(垃圾对象少就没必要回收)   3、当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。 1、引用计数 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。 原理 引用计数法的原理是每个对象维护一个ob_refcnt,用来记录当前对象被引用的次数,也就是来追踪到底有多少引用指向了这个对象。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。当引用计数为0时,该对象生命就结束了。 源码如下: /

Netty版本升级及线程模型详解

最后都变了- 提交于 2019-12-03 07:08:20
作者 李林锋 发布于 2015年2月7日 | 注意: GTLC全球技术领导力峰会 ,500+CTO技聚重新定义技术领导力! 18 讨论 分享到: 微博 微信 Facebook Twitter 有道云笔记 邮件分享 稍后阅读 我的阅读清单 1. 背景 1.1. Netty 3.X系列版本现状 根据对Netty社区部分用户的调查,结合Netty在其它开源项目中的使用情况,我们可以看出目前Netty商用的主流版本集中在3.X和4.X上,其中以Netty 3.X系列版本使用最为广泛。 Netty社区非常活跃,3.X系列版本从2011年2月7日发布的netty-3.2.4 Final版本到2014年12月17日发布的netty-3.10.0 Final版本,版本跨度达3年多,期间共推出了61个Final版本。 1.2. 升级还是坚守老版本 相比于其它开源项目,Netty用户的版本升级之路更加艰辛,最根本的原因就是Netty 4对Netty 3没有做到很好的前向兼容。 相关厂商内容 通过探针技术,实现Java应用程序自我防护 新Java,新未来 你离成为一位合格的技术领导者还有多远? 你了解技术领导与技术管理的差别吗? 相关赞助商 QCon全球软件开发大会上海站,2016年10月20日-22日,上海宝华万豪酒店, 精彩内容抢先看 ! 由于版本不兼容,大多数老版本使用者的想法就是既然升级这么麻烦

STL 一级/二级空间配置器

▼魔方 西西 提交于 2019-12-03 05:14:38
内碎片:需要3字节,系统分配4字节,剩下的1字节就是内碎片 外碎片:由于不断申请内存和归还内存使得内存中剩下很多小片段的内存,无法被利用 作用: (1)提高代码复用率,功能模块化。 (2)减少内存碎片问题。 (3)提高内存分配的效率。 (4)有内存不足时的应对措施。 (5)隐藏实际中对存储空间的分配及释放细节,确保所有被分配的存储空间都最终获得释放。 (5)考虑多线程状态。 考虑到小型区块可能导致的内存碎片问题,设置了两级空间配置器。分别为:一级空间配置器、二级空间配置器。当区块大于128字节,调用一级空间配置器;小于等于128字节,为了降低额外开销,用底层较复杂的二级空间配置器。 一级空间配置器 分为三个函数 Allocate用于分配空间,如果申请失败,用oom_alloc重新尝试申请。 Deallocate用于释放空间。 Reallocate用于根据需要自己调整已经存在的空间大小,如果申请调整失败,用oom_realloc尝试申请。 SGI二级空间配置器的原理是:当区块小于128字节,则以内存池(memory pool)管理,回收时管理一个用户归还的空间,类似于哈希桶。每次配置一块内存,并维护对应的自由链表(free_list)。为了方便管理,SGI二级配置器会对齐到8个字节。(例:需要30字节的空间,自动调整到32字节)。维护16个free_lists,各自管理大小分别为 8

SQLite剖析之动态内存分配

匿名 (未验证) 提交于 2019-12-03 00:19:01
SQLite剖析之动态内存分配 SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存、建立数据库文件的内存Cache、保存查询结果。 1、特性 SQLite内核和它的内存分配子系统提供以下特性: (1)对内存分配失败的健壮处理。如果一个内存分配请求失败(即malloc()或realloc()返回NULL),SQLite将释放未关联的缓存页,然后重新进行分配请求。如果失败,SQLite返回SQLITE_NOMEM给应用程序。 (2)无内存泄漏。应用程序负责销毁已分配的任何对象。例如应用程序必须使用sqlite3_finalize()结束每个预处理SQL语句,使用sqlite3_close关闭每个数据库连接。只要应用程序配合,即使在内存分配失败或系统出错的情况下SQLite也绝不会泄漏内存。 (3)内存使用限制。sqlite3_soft_heap_limit64()机制可以让应用程序设置SQLite的内存使用限制。SQLite会从缓存中重用内存,而不是分配新的内存,以满足设置的限制。 (4)零分配选项。应用程序可以在启动时给SQLite提供几个大块内存的缓冲区,SQLite将用这些缓冲区作为它所有内存分配的需要,不再调用系统的malloc()和free()。 (5)应用程序提供内存分配器。应用程序在启动时可以给SQLite提供可选的内存分配器

网络编程面试题整理(四)

故事扮演 提交于 2019-12-02 10:44:27
1:重传机制 TCP每发送一个报文段,就设置一次定时器。只要定时器设置的重发时间到而还没有收到确认,就要重发这一报文段。 TCP环境报文往返时间不定、有很大差别。 A、B在一个局域网络,往返时延很小 A、C在一个互联网内,往返时延很大 因此,A很难确定一个固定的、与B、C通信都适用的定时器时间。 TCP采用了一种自适应算法。这种算法记录每一个报文段发出的时间,以及收到相应的确认报文段的时间。这两个时间之差就是报文段的往返时延。将各个报文段的往返时延样本加权平均,就得出报文段的平均往返时延T。 2:ThreadLocal与其它同步机制的比较 首选了解什么是ThreadLocal:用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。 Threadlocal和其他所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对对象 加锁 来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致的分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的索等等。所有这些都是因为多个线程共享了该资源造成的。Threadlocal就从另一个角度来解决多线程的并发访问

Netty系列之Netty高性能之道

蹲街弑〆低调 提交于 2019-12-01 22:52:00
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于Java序列化+BIO(同步阻塞IO)的通信框架,性能提升了8倍多。 事实上,我对这个数据并不感到惊讶,根据我5年多的NIO编程经验,通过选择合适的NIO框架,加上高性能的压缩二进制编解码技术,精心的设计Reactor线程模型,达到上述性能指标是完全有可能的。 下面我们就一起来看下Netty是如何支持10W TPS的跨节点远程服务调用的,在正式开始讲解之前,我们先简单介绍下Netty。 1.2. Netty基础入门 Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。 作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。 2. Netty高性能之道 2.1. RPC调用的性能模型分析 2.1.1. 传统RPC调用性能差的三宗罪 网络传输方式问题

Netty高性能之道

北城以北 提交于 2019-12-01 22:50:02
1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用。相比于传统基于Java序列化+BIO(同步阻塞IO)的通信框架,性能提升了8倍多。 事实上,我对这个数据并不感到惊讶,根据我5年多的NIO编程经验,通过选择合适的NIO框架,加上高性能的压缩二进制编解码技术,精心的设计Reactor线程模型,达到上述性能指标是完全有可能的。 下面我们就一起来看下Netty是如何支持10W TPS的跨节点远程服务调用的,在正式开始讲解之前,我们先简单介绍下Netty。 1.2. Netty基础入门 Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。 作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。 2. Netty高性能之道 2.1. RPC调用的性能模型分析 2.1.1. 传统RPC调用性能差的三宗罪 网络传输方式问题

STL源码剖析——空间配置器Allocator#3 自由链表与内存池

旧城冷巷雨未停 提交于 2019-12-01 07:11:54
  上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请。但只是对其概念进行点到为止的认识,并未深入探究。这节就来学习一下自由链表的填充和内存池的内存分配机制。 refill()函数——重新填充自由链表   前情提要,从 上节 第二级配置器的源码中可以看到,在空间配置函数allocate()中,当所需的某号自由链表为空时,才会调用refill()函数来填充链表。refill()函数默认申请20块区块的内存(5行),但所得内存不一定就是20块,要看当前内存池的剩余情况和堆容量的情况,这个在学习chunk_alloc()函数时会详解讨论,然后将第零块返回给allocate()函数,allocate()函数再返回给真正申请内存的用户,剩余内存分成区块串接成自由链表。 1 template <bool threads, int inst> 2 void* __default_alloc_template<threads, inst>::refill(size_t n) 3 { 4 int nobjs = 20; //需要填充自由链表时,尝试分配20个区块作为自由链表的新结点 5 char * chunk = chunk_alloc(n, nobjs); //交给chunk_alloc去分配内存,后述 6 obj * __VOLATILE * my_free

c++ 内存池

狂风中的少年 提交于 2019-11-30 23:20:52
初始申请内存,将内存分为内存区,各个内存区以链表相连,每个内存区中又有内存块链表 #ifndef UNTITLED5_MEMORY_POOL_H #define UNTITLED5_MEMORY_POOL_H #include<stdint.h> #include <mutex> template<size_t BlockSize,size_t BlockNum =10> class MemoryPool { public: MemoryPool() { std::lock_guard<std::mutex>lock(mtx); free_block_head=NULL; mem_chunk_head=NULL; } ~MemoryPool() { std::lock_guard<std::mutex> lk(mtx); MemChunk *p; while(mem_chunk_head)//循环链表删除内存区 { p=mem_chunk_head->next; delete mem_chunk_head; mem_chunk_head= NULL; mem_chunk_head=p; } } void *allocate()//分配空间 { std::lock_guard<std::mutex>lk(mtx); if(!free_block_head) {//首内存块为空