leveldb Arena
背景
我们都知道,对于一个高性能的服务器端程序来说,内存的使用非常重要。C++提供了new/delete来管理内存的申请和释放,但是对于小对象来说,直接使用new/delete代价比较大,要付出额外的空间和时间,性价比不高。
另外,我们也要避免多次的申请和释放引起的内存碎片。一旦碎片到达一定程度,即使剩余内存总量够用,但由于缺乏足够的连续空闲空间,导致内存不够用的假象。
c++ STL为了避免内存碎片,实现一个复杂的内存池,leveldb中则没有那么复杂,只是实现了一个"一次性"内存池Arena。
在leveldb里面,并不是所有的地方都使用了这个内存池,主要是memtable使用,主要是用于临时存放用户的更新数据,由于更新的数据可能很小,所以这里使用内存池就很合适。
原理
为了避免小对象的频繁分配,需要减少对new的调用,最简单的做法就是申请大块的内存,多次分给客户。
leveldb用一个vector<char *>来保存所有的内存分配记录,默认每次申请4k的内存,记录下剩余指针和剩余内存字节数,每当有新的申请,如果当前剩余的字节能满足需要,则直接返回给用户,如果不能,对于超过1k的请求,直接new返回,小于1K的请求,则申请一个新的4k块,从中分配一部分给用户。
但是这样的一个问题就是当前块剩余的部分就浪费了,改进的方法,针对每个block都记录剩余字节,这样就需要遍历来查找合适的block,要付出一些性能的代价。google的做法是浪费就浪费吧:-)
至于释放,需要释放整个内存池来释放所占内存,这个和leveldb的需求有关,memtable不需要释放单次内存,flush到硬盘后整个memtable销毁。
Arena.h
//z 2014-06-05 10:48:50 L.209'47470 BG57IV3 T1840949363.K.F1370514324[T6,L108,R4,V118]
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- #ifndef STORAGE_LEVELDB_UTIL_ARENA_H_
- #define STORAGE_LEVELDB_UTIL_ARENA_H_
- #include <cstddef>
- #include <vector>
- #include <assert.h>
- #include <stdint.h>
- namespace leveldb
- {
- /*//z
- 思路:
- 先在上一次分配的内存块中查找是否剩余空间能否容纳当前申请的空间;如果足以容纳,直接使用剩余空间
- 否则视其大小重新分配一块空间:如果大于1024,直接分配一块新空间,大小与申请空间大小同
- 如果小于1024,说明上一块空间剩余空间小于1024,那么重新分配一块4096大小的空间,使用该空间来存放待申请的空间
- */
- 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&);
- };
- 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 > 0);
- //z 在一块直接分配好的内存上移动一下指针即可;事实上可能会存在很多的浪费。
- if (bytes <= alloc_bytes_remaining_)
- {
- char* result = alloc_ptr_;
- alloc_ptr_ += bytes;
- alloc_bytes_remaining_ -= bytes;
- return result;
- }
- //z 如果剩余控件不足与容纳,那么根据bytes大小决定是否重新分配一块标准大小的内存(4096),或者要是bytes大于1024,直接
- //z 分配其大小的内存,原标准块内存仍旧有用。
- //z 如果小于 1024 ,说明原标准块剩余内存不足以容纳1024,新分配一块标准块内存,用此来为bytes分配对应内存。
- return AllocateFallback(bytes);
- }
- }
- #endif // STORAGE_LEVELDB_UTIL_ARENA_H_
//z 2014-06-05 10:48:50 L.209'47470 BG57IV3 T1840949363.K.F1370514324[T6,L108,R4,V118]
arena.cc
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- #include "util/arena.h"
- #include <assert.h>
- namespace leveldb {
- //z 常量变量名k开头
- static const int kBlockSize = 4096;
- //z 初始化
- Arena::Arena() {
- blocks_memory_ = 0;
- alloc_ptr_ = NULL; // First allocation will allocate a block
- alloc_bytes_remaining_ = 0;
- }
- Arena::~Arena() {
- //z 删除申请的内存
- for (size_t i = 0; i < blocks_.size(); i++) {
- delete[] blocks_[i];
- }
- }
- char* Arena::AllocateFallback(size_t bytes) {
- //z 如果申请的bytes > 1024
- if (bytes > kBlockSize / 4) {
- // 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.
- //z 不大于1024时,分配一块标准大小的内存
- alloc_ptr_ = AllocateNewBlock(kBlockSize);
- alloc_bytes_remaining_ = kBlockSize;
- //z 指定返回的位置
- char* result = alloc_ptr_;
- //z 移动指针位置至空闲内存开始的地方
- alloc_ptr_ += bytes;
- //z 记录还剩下多少内存
- alloc_bytes_remaining_ -= bytes;
- return result;
- }
- char* Arena::AllocateAligned(size_t bytes) {
- //z 这个值是固定的,不用每次都求一次?但是代价非常小,求一次也无所为?
- const int align = sizeof(void*); // We'll align to pointer size
- assert((align & (align-1)) == 0); // Pointer size should be a power of 2
- //z 求的其余数
- size_t current_mod = reinterpret_cast<uintptr_t>(alloc_ptr_) & (align-1);
- size_t slop = (current_mod == 0 ? 0 : align - current_mod);
- size_t needed = bytes + slop;
- char* result;
- //z 如果剩余的空间足以容纳所需要的内存
- if (needed <= alloc_bytes_remaining_) {
- //z 对齐返回地址
- result = alloc_ptr_ + slop;
- alloc_ptr_ += needed;
- alloc_bytes_remaining_ -= needed;
- } else {
- // AllocateFallback always returned aligned memory
- //z 否则直接分配一块新的内存
- //z 在这种情况下这块内存可能很小
- result = AllocateFallback(bytes);
- }
- //z 确保返回地址是对齐的
- assert((reinterpret_cast<uintptr_t>(result) & (align-1)) == 0);
- return result;
- }
- //z 在不小于一个page的时候,直接采用这种方式
- char* Arena::AllocateNewBlock(size_t block_bytes) {
- char* result = new char[block_bytes];
- blocks_memory_ += block_bytes;
- blocks_.push_back(result);
- return result;
- }
- }
//z 2014-06-05 10:48:50 L.209'47470 BG57IV3 T1840949363.K.F1370514324[T6,L108,R4,V118]
leveldb Arena的更多相关文章
- leveldb Arena源码分析
前言 对于一个高性能的服务器程序来说,内存的使用非常重要.C++提供new/delete来管理内存的申请和释放,但是对于小对象来说,直接使用new/delete代价比较大,要付出额外的空间和时间,性价 ...
- LevelDB(v1.3) 源码阅读之 Arena(内存管理器)
LevelDB(v1.3) 源码阅读系列使用 LevelDB v1.3 版本的代码,可以通过如下方式下载并切换到 v1.3 版本的代码: $ git clone https://github.com/ ...
- leveldb分析——Arena内存管理
leveldb中实现了一个简单的内存管理工具Arena,其基本思想为:先预先向系统申请一块内存,此后需要申请内存时,直接到预先分配的内存中申请. 那么这样做的目的是什么呢? (1)避免了频率地进行ma ...
- LevelDB源码分析之:arena内存管理
一.原理 arena是LevelDB内部实现的内存池. 我们知道,对于一个高性能的服务器端程序来说,内存的使用非常重要.C++提供了new/delete来管理内存的申请和释放,但是对于小对象来说,直接 ...
- leveldb源码分析之内存池Arena
转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...
- LevelDB 源码解析之 Arena
GitHub: https://github.com/storagezhang Emai: debugzhang@163.com 华为云社区: https://bbs.huaweicloud.com/ ...
- LevelDB学习笔记 (3): 长文解析memtable、跳表和内存池Arena
LevelDB学习笔记 (3): 长文解析memtable.跳表和内存池Arena 1. MemTable的基本信息 我们前面说过leveldb的所有数据都会先写入memtable中,在leveldb ...
- LevelDB源码剖析
LevelDB的公共部件并不复杂,但为了更好的理解其各个核心模块的实现,此处挑几个关键的部件先行备忘. Arena(内存领地) Arena类用于内存管理,其存在的价值在于: 提高程序性能,减少Heap ...
- 【转】Leveldb源码分析——1
先来看看Leveldb的基本框架,几大关键组件,如图1-1所示. Leveldb是一种基于operation log的文件系统,是Log-Structured-Merge Tree的典型实现.LSM源 ...
随机推荐
- [傻瓜式一步到位] 阿里云服务器Centos上部署一个Flask项目
网络上关于flask部署Centos的教程有挺多,不过也很杂乱. 在我第一次将flask上传到centos服务器中遇到了不少问题,也费了挺大的劲. 在参考了一些教程,并综合了几个教程之后才将flask ...
- 40.数组中只出现一次的数字(python)
题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 思路 将数组的因为就两个数只出现一次,所以,这些数字做异或之后,得到的结果是这两个数做异或的 ...
- PHP中变量声明和定义的区别
先记录一下(不知道PHP是不是一样,但是C语言是这样的):把建立空间的声明称之为“定义”,而把不需要建立存储空间的声明称之为“声明”.声明的最终目的是为了提前使用,即在定义之前使用,如果不需要提前使用 ...
- [JZOJ6247]【NOI2019模拟2019.6.27】C【计数】
Description n<=200000 Solution 比赛时没做出这道题真的太弟弟了 首先我们从小到大插入数i,考虑B中有多少个区间的最大值为i 恰好出现的次数不太好计算,我们考虑计算最 ...
- CodeForces451E Devu and Flowers
题目链接 问题分析 没有想到母函数的做法-- 其实直接看题思路挺简单的.发现如果每种花都有无限多的话,问题变得十分简单,答案就是\(s+n-1\choose n - 1\).然后发现\(n\)只有\( ...
- 12.Python数值类型(整形、浮点型和复数)及其用法
实际开发中,我们经常需要使用数字记录游戏中用户的得分.游戏中角色的生命值.伤害值等信息,Python 语言提供了数值类型用于保存这些数值. 需要注意的是,Python 中这些数值类型都是不可改变的,也 ...
- Upload-libs通关详解
Uplo ad-labs—详解 1前端验证绕过 前端验证绕过可以直接用burp万能绕过前端JS脚本 方法先上传一张jpg Burp改包然后改后缀 上传成功 2Content-Type方式绕过 此绕过方 ...
- Redis大 key的发现与删除方法全解析
个推作为国内第三方推送市场的早期进入者,专注于为开发者提供高效稳定的推送服务,经过9年的积累和发展,服务了包括新浪.滴滴在内的数十万APP.由于我们推送业务对并发量.速度要求很高,为此,我们选择了高性 ...
- 解决cron不执行的问题
在FreeBSD5.4下面做开发,需要定期备份mysql数据,开始在网上找了bash的脚本,但是执行无效,一怒之下,使用php来写,嘿嘿,其实php写脚本也不错滴.备份其实就是把mysql的数据库文件 ...
- spark 笔记 4:Apache Hadoop YARN: Yet Another Resource Negotiator
spark支持YARN做资源调度器,所以YARN的原理还是应该知道的:http://www.socc2013.org/home/program/a5-vavilapalli.pdf 但总体来说, ...