OS(1)之内存Memory篇


title: 内存Memory
date: 2020-09-25 19:07:05
categories: 3d引擎
mathjax: false


主要文件 core/os/memory.hcore/os/memory.cpp

  1. 封装原始的malloc、free、new、delete。好处是添加自定义引用头和内存统计分析等。

  2.    //c 风格接口
       memalloc()
       memrealloc()
       memfree()
  3. //c++ 风格接口
    memnew( Class / Class(args) )
    memdelete( instance )
    
    memnew_arr( Class , amount )
    memdelete_arr( pointer to array )
  4. todo

    1. 原子操作 加减。
    2. 动态内存 poolvector<>模板
  1. 使用类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();
    };
  2. 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);  
  }
}
```
  1. 默认内存申请器

    ``` 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); }
    };
    ```
  2. 重载 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);
    }
  3. 统一使用接口

    //统一接口 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);
    }

文章作者: Yonggang Long
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yonggang Long !
 上一篇
2022-08-10 Yonggang Long
下一篇 
2022-08-10 Yonggang Long
  目录