【lesson11】高并发内存池性能优化

文章讨论了高并发情况下内存池性能下降的问题,主要集中在MapObjectToSpan函数上的锁消耗。通过引入基数树数据结构,特别是单层、两层和三层基数树,优化了映射关系的查找,实现了线程安全且提高了性能。作者在PageCache类中展示了如何替换map使用一层基数树,并给出了相应的代码实现和优化效果对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高并发内存池性能问题

我们知道,我们实现的高并发内存池存在大量的申请锁和,释放锁,而这样就会导致我们的性能比不上原来的malloc
在这里插入图片描述

性能分析:
在这里插入图片描述
通过报告,我们发现性能差的很大原因是因为MapObjectToSpan
而MapObjectToSpan耗费性能的原因是因为锁的问题,频繁的申请锁和释放锁会很耗费性能。

// 获取从对象到span的映射
Span* PageCache::MapObjectToSpan(void* obj)
{
   
	PAGE_ID id = ((PAGE_ID)obj >> PAGE_SHIFT);

	std::unique_lock<std::mutex> lock(_pageMtx);
	auto ret = _idSpanMap.find(id);
	if (ret != _idSpanMap.end())
	{
   
		return ret->second;
	}
	else
	{
   
		assert(false);
		return nullptr;
	}
}

而这是我们就要对其进行优化,我们查看tcmalloc发现,他用一个叫基数树的数据结构解决了这方面的问题。
基数树也是存储id和span的映射关系。

基数树优化性能

代码

一层基数树

#pragma once
#include"Common.h"
// Single-level array
template <int BITS>
class TCMalloc_PageMap1 {
   
private:
	static const int LENGTH = 1 << BITS;
	void** array_;

public:
	typedef uintptr_t Number;

	//explicit TCMalloc_PageMap1(void* (*allocator)(size_t)) {
   
	explicit TCMalloc_PageMap1() {
   
		//array_ = reinterpret_cast<void**>((*allocator)(sizeof(void*) << BITS));
		size_t size = sizeof(void*) << BITS;
		size_t alignSize = SizeClass::_RoundUp(size, 1<<PAGE_SHIFT);
		array_ = (void**)SystemAlloc(alignSize>>PAGE_SHIFT);
		memset(array_, 0, sizeof(void*) << BITS);
	}

	// Return the current value for KEY.  Returns NULL if not yet set,
	// or if k is out of range.
	void* get(Number k) const {
   
		if ((k >> BITS) > 0) {
   
			return NULL;
		}
		return array_[k];
	}

	// REQUIRES "k" is in range "[0,2^BITS-1]".
	// REQUIRES "k" has been ensured before.
	//
	// Sets the value 'v' for key 'k'.
	void set(Number k, void* v) {
   
		array_[k] = v;
	}
};

一层基数树,是在映射之前直接开辟219个指针大小的空间。
所以每个位置都能存储指针,而要存的_pageid直接映射到桶对应的下标处
在这里插入图片描述

两层基数树

#pragma once
#include"Common.h"
// Two-level radix tree
template <int BITS>
class TCMalloc_PageMap2 {
   
private:
	// Put 32 entries in the root and (2^BITS)/32 entries in each leaf.
	static const int ROOT_BITS = 5;
	static const int ROOT_LENGTH = 1 << ROOT_BITS;

	static const int LEAF_BITS = BITS - ROOT_BITS;
	static const int LEAF_LENGTH = 1 << LEAF_BITS;

	// Leaf node
	struct Leaf {
   
		void* values[LEAF_LENGTH];
	};

	Leaf* root_[ROOT_LENGTH];             // Pointers to 32 child nodes
	void* (*allocator_)(size_t);          // Memory allocator

public:
	typedef uintptr_t Number;

	//explicit TCMalloc_PageMap2(void* (*allocator)(size_t)) {
   
	explicit TCMalloc_PageMap2() {
   
		//allocator_ = allocator;
		memset(root_, 0, sizeof(root_));

		PreallocateMoreMemory();
	}

	void* get(Number k) const {
   
		const Number i1 = k >> LEAF_BITS;
		const Number i2 = k & 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值