leveldb中实现了一个简单的内存管理工具Arena,其基本思想为:先预先向系统申请一块内存,此后需要申请内存时,直接到预先分配的内存中申请。

那么这样做的目的是什么呢?

(1)避免了频率地进行malloc/new和free/delete操作,同时对于内存管理变得简单,对于内存的释放工作交给Arena。

(2)避免造成大量的内存碎片。(还需去了解一下)

下面看具体的源码分析:

Arena定义:

class Arena {
public:
Arena();
~Arena(); // Return a pointer to a newly allocated memory block of "bytes" bytes.
char* Allocate(size_t bytes); // Allocate memory with the normal alignment guarantees provided by malloc
char* AllocateAligned(size_t bytes); // Returns an estimate of the total memory usage of data allocated
// by the arena (including space allocated but not yet used for user
// allocations).
size_t MemoryUsage() const {
return blocks_memory_ + blocks_.capacity() * sizeof(char*);
} private:
char* AllocateFallback(size_t bytes);
char* AllocateNewBlock(size_t block_bytes); // Allocation state
char* alloc_ptr_;
size_t alloc_bytes_remaining_; // Array of new[] allocated memory blocks
std::vector<char*> blocks_; // Bytes of memory in blocks allocated so far
size_t blocks_memory_; // No copying allowed
Arena(const Arena&);
void operator=(const Arena&);
};

Arena提供两种分配方式:所分配的内存严格对齐、不一定严格对齐的分配方式。每次预先分配的4K(为什么是4K?)保存到blocks_ vector中,最后统一释放。这种内存管理方式是具有一定的适用范围,如需不断分配小内存,最终一并全释放的场景。对于leveldb来说,memtable恰好就是这样的,每次向memtable中insert一条k/v时,就申请一块内存,当memtable被flush到磁盘且不再使用时,将整个memtable释放掉。

inline char* Arena::Allocate(size_t bytes) {
// The semantics of what to return are a bit messy if we allow
// 0-byte allocations, so we disallow them here (we don't need
// them for our internal use).
assert(bytes > );
if (bytes <= alloc_bytes_remaining_) {
char* result = alloc_ptr_;
alloc_ptr_ += bytes;
alloc_bytes_remaining_ -= bytes;
return result;
}
return AllocateFallback(bytes); //预先分配的不足
}
char* Arena::AllocateFallback(size_t bytes) {
if (bytes > kBlockSize / ) {
// Object is more than a quarter of our block size. Allocate it separately
// to avoid wasting too much space in leftover bytes.
char* result = AllocateNewBlock(bytes); ///对于大内存,直接单独给分配一块,原先预分配的内存还能使用
return result;
} // We waste the remaining space in the current block. 预分配的内存剩下的已很少,所以直接重新分配一块,也就是说浪费了一点内存
alloc_ptr_ = AllocateNewBlock(kBlockSize);
alloc_bytes_remaining_ = kBlockSize; char* result = alloc_ptr_;
alloc_ptr_ += bytes;
alloc_bytes_remaining_ -= bytes;
return result;
}

下面来看下严格对齐的分配方式

char* Arena::AllocateAligned(size_t bytes) {
const int align = sizeof(void*); // We'll align to pointer size
assert((align & (align-)) == ); // Pointer size should be a power of 2
size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-); ///计算出alloc_ptr_ % align
size_t slop = (current_mod == ? : align - current_mod); ///对齐还需要向前移动的大小
size_t needed = bytes + slop;
char* result;
if (needed <= alloc_bytes_remaining_) {
result = alloc_ptr_ + slop;
alloc_ptr_ += needed;
alloc_bytes_remaining_ -= needed;
} else {
// AllocateFallback always returned aligned memory
result = AllocateFallback(bytes);
}
assert((reinterpret_cast<uintptr_t>(result) & (align-)) == );
return result;
} char* Arena::AllocateNewBlock(size_t block_bytes) {
char* result = new char[block_bytes];
blocks_memory_ += block_bytes;
blocks_.push_back(result);
return result;
}

leveldb分析——Arena内存管理的更多相关文章

  1. Memcached源码分析之内存管理

    先再说明一下,我本次分析的memcached版本是1.4.20,有些旧的版本关于内存管理的机制和数据结构与1.4.20有一定的差异(本文中会提到). 一)模型分析在开始解剖memcached关于内存管 ...

  2. iOS的内存分析和内存管理

    iOS的内存分析和内存管理 [内存管理]一直是iOS开发中的一个重点. 本文就带你从内存分析开始一步步了解内存的占用情况,从真实的情况中领悟真正项目开发过程中的内存的使用情况. 注:本文默认你熟悉 M ...

  3. redis 源代码分析(一) 内存管理

    一,redis内存管理介绍 redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中 ...

  4. MySQL系列:innodb源代码分析之内存管理

    在innodb中实现了自己的内存池系统和内存堆分配系统,在innodb的内存管理系统中,大致分为三个部分:基础的内存块分配管理.内存伙伴分配器和内存堆分配器.innodb定义和实现内存池的主要目的是提 ...

  5. cocos2d-x 源代码分析 : Ref (CCObject) 源代码分析 cocos2d-x内存管理策略

    从源代码版本号3.x.转载请注明 cocos2d-x 总的文件夹的源代码分析: http://blog.csdn.net/u011225840/article/details/31743129 1.R ...

  6. [转]linux内核分析笔记----内存管理

    转自:http://blog.csdn.net/Baiduluckyboy/article/details/9667933 内存管理,不用多说,言简意赅.在内核里分配内存还真不是件容易的事情,根本上是 ...

  7. linux 内核源代码情景分析——linux 内存管理的基本框架

    386 CPU中的页式存管的基本思路是:通过页面目录和页面表分两个层次实现从线性地址到物理地址的映射.这种映射模式在大多数情况下可以节省页面表所占用的空间.因为大多数进程不会用到整个虚存空间,在虚存空 ...

  8. LevelDB源码分析之:arena内存管理

    一.原理 arena是LevelDB内部实现的内存池. 我们知道,对于一个高性能的服务器端程序来说,内存的使用非常重要.C++提供了new/delete来管理内存的申请和释放,但是对于小对象来说,直接 ...

  9. linux内核分析之内存管理

    1.struct page /* Each physical page in the system has a struct page associated with * it to keep tra ...

随机推荐

  1. Python+Selenium(webdriver常用API)

    总结了Python+selenium常用的一些方法函数,以后有新增再随时更新: 加载浏览器驱动: webdriver.Firefox() 打开页面:get() 关闭浏览器:quit() 最大化窗口:  ...

  2. 3、在Shell程序中使用的参数

    学习目标位置参数内部参数 如同ls命令可以接受目录等作为它的参数一样,在Shell编程时同样可以使用参数.Shell程序中的参数分为位置参数和内部参数等. 12-3-1 位置参数由系统提供的参数称为位 ...

  3. html锚点(mao dian)--特殊的超链接

    锚点(anchor):其实就是超链接的一种,一种特殊的超链接 普通的超链接,<a href="路径"></a> 是跳转到不同的页面 而锚点,<a hr ...

  4. Django models.py创建数据库

    创建完后初始化数据库 在命令行里输入: 回车后出现 继续命令行输入:

  5. FileReader实现上传图片前本地预览

    平时做图片上传预览时如果没有特殊的要求就直接先把图片传到后台去,成功之后拿到URL再渲染到页面上.或者使用前端插件.这篇博客使用的是HTML5的新特性——FileReader.由于兼容性,这种方法不适 ...

  6. php根据IP获取所在省份-淘宝api接口

    这里用的file_put_contents,你也可以用别的,直接怼代码: //拼接传递的参数$ip = '175.12.53.12' $opts = array( 'http'=>array( ...

  7. maven配置编译器的版本

    发现每次启动idea时,项目里很多红色错误,都是的编译器版本不对,每次都要手动修改. 其实在pom里把默认编译器版本加进去就好了. <build> <plugins> < ...

  8. C++命名空间使用代码

    namesp.h #pragma once #include <string> namespace pers { using namespace std; struct Person { ...

  9. Java基础(三)选择和循环结构

    一.选择结构,条件判断 1.if 语句 一个 if 语句包含一个布尔表达式和一条或多条语句.如果布尔表达式的值为 true,则执行 if 语句中的代码块,否则执行 if 语句块后面的代码. impor ...

  10. hibernate cascade的真正含义

    hibernate cascade 是 @OneToOne @OneToMany @ManyToOne @ManyToMany等注解的属性,表示级联操作. /** * (Optional) The o ...