¿Cuál es el principio del grupo de memoria? |Implementación de simulación simple del grupo de memoria|Preparación para el aprendizaje del grupo de memoria de alta simultaneidad tcmalloc

prefacio

那么这里博主先安利一些干货满满的专栏了!

这两个都是博主在学习Linux操作系统过程中的记录,希望对大家的学习有帮助!

操作系统Operating Syshttps://blog.csdn.net/yu_cblog/category_12165502.html?spm=1001.2014.3001.5482Linux Sys https://blog.csdn.net/yu_cblog/category_11786077.html?spm=1001.2014.3001.5482 Estas dos son columnas para que los bloggers aprendan estructuras de datos y simulen varios contenedores en la biblioteca de plantillas estándar STL.

Análisis de código fuente STL https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482 estructura de datos desgarrada a mano https://blog.csdn.net/yu_cblog/category_11490888.html


¿Qué es un grupo de memoria?

Por lo tanto, recientemente los bloggers van a empezar a aprender la tecnología tcmalloc de Google. De hecho, es un grupo de memoria de alta concurrencia con extrema eficiencia. En preparación para el siguiente proyecto de grupo de memoria de alta concurrencia, hoy les traeré un código de demostración simple de esta sencilla tecnología de implementación de grupos de memoria.

Entonces, el código de este blog, este es el código de demostración del grupo de memoria, ¡el grupo de memoria real es mucho más complicado que esto! El código aquí es solo para fines educativos. La tecnología tcmalloc es el objetivo de aprender el conjunto de memoria.

¿Qué es un grupo de memoria?

Un grupo de memoria es una técnica utilizada para gestionar la asignación y desasignación de memoria en programas informáticos. Es similar a un área de almacenamiento de memoria preparada previamente desde la cual los programas pueden obtener bloques de memoria en lugar de preguntar con frecuencia al sistema operativo. Este enfoque es más eficiente porque hay menos sobrecarga en la asignación y liberación de bloques de memoria y se evita la fragmentación. El grupo de memoria mejora el rendimiento y la velocidad de respuesta del programa, y ​​es especialmente adecuado para escenarios donde los objetos se crean y destruyen con frecuencia, como servidores web y programación concurrente. El malloc del lenguaje C es esencialmente un grupo de memoria.

Fundamentos de los grupos de memoria

Para manejar de manera más eficiente la adquisición de recursos de la memoria, la adquisición de recursos de la memoria y la liberación de recursos a la memoria, los grupos de memoria generalmente hacen lo siguiente:

Para fácil comprensión de todos, el blogger lo dijo de una manera más popular:

  • Cuando se inicializa el grupo de memoria, se requiere un gran recurso directamente de la memoria.
  • Al obtener recursos del grupo de memoria, corte una parte del gran bloque de memoria obtenido de la inicialización en este momento y déselo a la capa superior para que lo use.
  • Cuando un proceso libera recursos para el grupo de memoria, no los libera directamente para el sistema, sino que primero le da el espacio no utilizado al grupo de memoria, y el grupo de memoria mantiene una lista de enlace único para unir los recursos devueltos.
  • Cuando se agote el gran bloque de memoria, solicite al sistema nueva memoria.
  • Cuando el proceso solicita recursos, primero obtiene los recursos devueltos de la lista enlazada, si no hay recursos en la lista enlazada, solicita recursos al sistema.

ObjectPool.hpp


#ifndef __OBJECT_POOL__
#define __OBJECT_POOL__

#include <iostream>
#include <vector>
// #include "../utils/Log.hpp"  // 大家下载代码的时候可以暂时不要日志

#define __DEFAULT_KB__ 128

/*
    其实这里直接使用malloc的,malloc其实自己就是C语言的一个内存池,
    其实我们可以直接用系统调用,跳过malloc,这样测试现象更明显
    调用SystemAlloc替换malloc即可
*/

inline static void *SystemAlloc(size_t kpage)
{
    void *ptr = nullptr;
#ifdef _WIN32
    *ptr = VirtualAlloc(0, kpage * (1 << 12), MEM_COMMIT | MEM_RESERVE,
                             PAGE_READWRITE);
#else
    // linux下brk mmap等 #endif
    
    if (ptr == nullptr)
        throw std::bad_alloc();
    return ptr;
#endif
}

template <class T>
class ObjectPool
{
private:
    char *__memory = nullptr;    // char 方便切
    size_t __remain_bytes = 0;   // 大块内存在切的过程中剩余的字节数
    void *__free_list = nullptr; // 还回来的时候形成的自由链表
public:
    T *New()
    {
        T *obj = nullptr;
        // 不够空间 首选是把还回来的内存块对象进行再次利用
        if (__free_list)
        {
            // 头删
            void *next = *((void **)__free_list);
            obj = (T *)__free_list;
            __free_list = next;
            return obj;
        }
        if (__remain_bytes < sizeof(T))
        {
            // 空间不够了,要重新开一个空间
            __remain_bytes = __DEFAULT_KB__ * 1024;
            __memory = (char *)malloc(__remain_bytes);
            if (__memory == nullptr)
            {
                throw std::bad_alloc();
                // logMessage(ERROR, "ObjectPool::New() malloc error");
            }
        }
        obj = (T *)__memory;
        size_t obj_size = sizeof(T) < sizeof(void *) ? sizeof(void *) : sizeof(T); // 小于一个指针的大小就给一个指针的大小就行
        __memory += obj_size;
        __remain_bytes -= obj_size;
        // 定位new,显示调用T的构造函数,让T初始化一下
        new (obj) T;
        return obj;
    }
    void Delete(T *obj)
    {
        // 这样写无论是第一次插入还是后面的插入,都可以
        // 这样写无论是32位还是64位,都可以
        obj->~T(); // 显示调用析构函数
        *(void **)obj = __free_list;
        __free_list = obj;
    }
};

#endif

testPerf.hpp

Se utiliza para probar el rendimiento de este grupo de memoria simple


#include "ObjectPool.hpp"

struct TreeNode
{
    int _val;
    TreeNode *_left;
    TreeNode *_right;
    TreeNode()
        : _val(0), _left(nullptr), _right(nullptr)
    {
    }
};
void TestObjectPool()
{
    // 申请释放的轮次
    const size_t Rounds = 5;
    // 每轮申请释放多少次
    const size_t N = 10000000;
    size_t begin1 = clock();
    std::vector<TreeNode *> v1;
    v1.reserve(N);
    for (size_t j = 0; j < Rounds; ++j)
    {
        for (int i = 0; i < N; ++i)
        {
            v1.push_back(new TreeNode);
        }
        for (int i = 0; i < N; ++i)
        {
            delete v1[i];
        }
        v1.clear();
    }
    size_t end1 = clock();
    ObjectPool<TreeNode> TNPool;
    size_t begin2 = clock();
    std::vector<TreeNode *> v2;
    v2.reserve(N);
    for (size_t j = 0; j < Rounds; ++j)
    {
        for (int i = 0; i < N; ++i)
        {
            v2.push_back(TNPool.New());
        }
        for (int i = 0; i < N; ++i)
        {
            TNPool.Delete(v2[i]);
        }
        v2.clear();
    }
    size_t end2 = clock();
    std::cout << "new cost time:" << end1 - begin1 << std::endl;
    std::cout << "object pool cost time:" << end2 - begin2 << std::endl;
}

prueba.cc

#include "testPerf.hpp"
int main()
{
    TestObjectPool();
    return 0;
}

Resultados de la prueba

Supongo que te gusta

Origin blog.csdn.net/Yu_Cblog/article/details/131741601
Recomendado
Clasificación