OS(1)之内存Memory篇
title: 内存Memory
date: 2020-09-25 19:07:05
categories: 3d引擎
mathjax: false
主要文件 core/os/memory.h 、core/os/memory.cpp
封装原始的malloc、free、new、delete。好处是添加自定义引用头和内存统计分析等。
//c 风格接口 memalloc() memrealloc() memfree()//c++ 风格接口 memnew( Class / Class(args) ) memdelete( instance ) memnew_arr( Class , amount ) memdelete_arr( pointer to array )todo
- 原子操作 加减。
- 动态内存 poolvector<>模板
使用类
Memory静态成员,全局唯一统计和调用。class Memory { Memory(); #ifdef DEBUG_ENABLED static uint64_t mem_usage; // 内存使用量,申请和释放进行统计 static uint64_t max_usage; // #endif static uint64_t alloc_count;//内存块个数,申请和释放进行统计 public: //封装原始申请函数,debug or p_pad_align为true 时进行统计 static void *alloc_static(size_t p_bytes, bool p_pad_align = false); //封装原始申请函数,debug or p_pad_align为true 时进行统计 static void *realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align = false); //封装原始释放函数,debug or p_pad_align为true 时进行统计 static void free_static(void *p_ptr, bool p_pad_align = false); static uint64_t get_mem_available(); static uint64_t get_mem_usage(); static uint64_t get_mem_max_usage(); };Memory 实现
``` cpp
ifdef DEBUG_ENABLED // debug 情况才有用并静态初始化
uint64_t Memory::mem_usage = 0;
uint64_t Memory::max_usage = 0;endif
uint64_t Memory::alloc_count = 0;
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { # ifdef DEBUG_ENABLED bool prepad = true;
else
bool prepad = p_pad_align; # endif
//头部固定 16字节(可以容纳 四个个int32, 两个个int64) void *mem = malloc(p_bytes + (prepad ? PAD_ALIGN : 0));
//malloc 失败判断 ERR_FAIL_COND_V(!mem, nullptr);
//递增使用的内存块,volatile关键字限制,保证准确性,cpu缓存 atomic_increment(&alloc_count);
if (prepad) { //前8字节放用户使用的大小。 uint64_t s = (uint64_t )mem; s = p_bytes; //内存头 s8 , uint8_t 一个字节+ PAD_ALIGN(16字节),偏移到用户地址,return uint8_t s8 = (uint8_t *)mem;
# ifdef DEBUG_ENABLED
//统计内存总字节数 atomic_add(&mem_usage, p_bytes); //原子交换 todo atomic_exchange_if_greater(&max_usage, mem_usage); # endif return s8 + PAD_ALIGN; } else { return mem; }void _Memory::realloc_static(void _p_memory, size_t p_bytes, bool p_pad_align) { if (p_memory == nullptr) { return alloc_static(p_bytes, p_pad_align); } uint8_t mem = (uint8_t )p_memory;
#ifdef DEBUG_ENABLED bool prepad = true; #else bool prepad = p_pad_align; #endif if (prepad) { mem -= PAD_ALIGN; uint64_t s = (uint64_t )mem; #ifdef DEBUG_ENABLED if (p_bytes > s) { atomic_add(&mem_usage, p_bytes - s); atomic_exchange_if_greater(&max_usage, mem_usage); } else { atomic_sub(&mem_usage, s - p_bytes); } #endif if (p_bytes == 0) { free(mem); return nullptr; } else { s = p_bytes; mem = (uint8_t )realloc(mem, p_bytes + PAD_ALIGN); ERR_FAIL_COND_V(!mem, nullptr); s = (uint64_t )mem; s = p_bytes; return mem + PAD_ALIGN; } } else { mem = (uint8_t )realloc(mem, p_bytes); ERR_FAIL_COND_V(mem == nullptr && p_bytes > 0, nullptr); return mem; }
}
void Memory::free_static(void *p_ptr, bool p_pad_align) {
ERR_FAIL_COND(p_ptr == nullptr);
uint8_t _mem = (uint8_t _)p_ptr;
# ifdef DEBUG_ENABLED
bool prepad = true;
# else
bool prepad = p_pad_align;
# endif
// 原子减 内存块数量
atomic_decrement(&alloc_count);
if (prepad) {
// 跳到mem 原始头,进行free
mem -= PAD_ALIGN;
# ifdef DEBUG_ENABLED
uint64_t *s = (uint64_t *)mem;
// 原子减 内存字节数
atomic_sub(&mem_usage, *s);
# endif
free(mem);
} else {
free(mem);
}
}
```
默认内存申请器
``` cpp //简单的包一层的申请和释放器 class DefaultAllocator { public: _FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, false); } _FORCE_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr, false); } }; ```重载 new、delete、new []、delete[], 目的是封装,最终都统一使用 Memory'静态方法,调用malloc, free.
//1. new重载1 void *operator new(size_t p_size, const char *p_description); void *operator new(size_t p_size, const char *p_description) { return Memory::alloc_static(p_size, false); } //1. new重载2 void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) { return p_allocfunc(p_size); } //1. new重载3 暂时无用 void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); _ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) { //void *failptr=0; //ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */ return p_pointer; } // 2. delete 重载1, 目的是限制直接使用delete, 使用统一的释放方法。 void operator delete(void *p_mem, const char *p_description); void operator delete(void *p_mem, const char *p_description) { CRASH_NOW_MSG("Call to placement delete should not happen."); } //2. delete 重载2, 目的是限制直接使用delete, 使用统一的释放方法。 void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)); void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) { CRASH_NOW_MSG("Call to placement delete should not happen."); } //2. delete 重载3, 目的是限制直接使用delete, 使用统一的释放方法。 void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description); void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) { CRASH_NOW_MSG("Call to placement delete should not happen."); } // 3. new[] 操作, 地址--> 记录len到头部数据->for eles template <typename T> T *memnew_arr_template(size_t p_elements, const char *p_descr = "") { if (p_elements == 0) { return nullptr; } /** overloading operator new[] cannot be done , because it may not return the real allocated address (it may pad the 'element count' before the actual array). Because of that, it must be done by hand. This is the same strategy used by std::vector, and the Vector class, so it should be safe.*/ size_t len = sizeof(T) * p_elements; uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true); T *failptr = nullptr; //get rid of a warning ERR_FAIL_COND_V(!mem, failptr); *(mem - 1) = p_elements; if (!__has_trivial_constructor(T)) { T *elems = (T *)mem; /* call operator new */ for (size_t i = 0; i < p_elements; i++) { new (&elems[i], sizeof(T), p_descr) T; } } return (T *)mem; } // 4. delete [],new[] 逆向顺序。 template <typename T> void memdelete_arr(T *p_class) { uint64_t *ptr = (uint64_t *)p_class; if (!__has_trivial_destructor(T)) { uint64_t elem_count = *(ptr - 1); for (uint64_t i = 0; i < elem_count; i++) { p_class[i].~T(); } } Memory::free_static(ptr, true); }统一使用接口
//统一接口 memalloc、memrealloc、memfree #define memalloc(m_size) Memory::alloc_static(m_size) #define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size) #define memfree(m_size) Memory::free_static(m_size) // memdelete,prehandler(目前空实现)--> 析构函数 --> 统一free接口 template <class T> void memdelete(T *p_class) { if (!predelete_handler(p_class)) { return; // doesn't want to be deleted } if (!__has_trivial_destructor(T)) { p_class->~T(); } Memory::free_static(p_class, false); } //指定内存申请器进行释放。 template <class T, class A> void memdelete_allocator(T *p_class) { if (!predelete_handler(p_class)) { return; // doesn't want to be deleted } if (!__has_trivial_destructor(T)) { p_class->~T(); } A::free(p_class); } template <class T, class A> void memdelete_allocator(T *p_class) { if (!predelete_handler(p_class)) { return; // doesn't want to be deleted } if (!__has_trivial_destructor(T)) { p_class->~T(); } A::free(p_class); }