当前位置:   article > 正文

超详细NCNN内存分配算法(小白必看,不懂打我)_ncnn 内存泄漏

ncnn 内存泄漏

NCNN是一款高效易用的深度学习推理框架,支持各种神经网络模型,如pytorch、tensorflow、onnx等,以及多种硬件后端,如x86、arm、riscv、mips、vulkan等,本文详细介绍内存分配算法。(从各个博客进行整理,争取以详细易懂的方式讲解这个算法。

字节分配算法

问题:分配n字节 ,以 align字节为对齐字节。

  1. #原始算法
  2. unsigned int calc_align(unsigned int n,unsigned align)
  3. {
  4.     if ( n / align * align == n)
  5.             return n;
  6.         return  (n / align + 1* align;
  7. }

返回能容纳n个字节的整除align个字节的最小空间字节数。

  1. #进阶版算法  
  2. unsigned int calc_align(unsigned int n,unsigned int align)
  3. {
  4.     return (n+ align - 1) & ~(align - 1);
  5. }

难点1

理解 (n + align - 1) & ~(align - 1)
由于,可得

为向上对齐,可能进位,使得分配字节为align倍数内能容纳完n个字节。

用于截断:
由于

为取反码,那么

,即,那么,就刚好囊括大于align字节数的范围。无视低于align的部分,因为前面是n+align-1,多余的align-1可以去除。

NCNN写法

NCNN是这么写的。

  1. static inline size_t alignSize(size_t sz, int n)
  2. {
  3.     return (sz + n-1) & -n;
  4. }

难点2

为什么
常识:负数补码为取负+1
那么这里,若即二进制得
,也就是前面所说的覆盖大于等于align的字节数范围。
同时也就是前面所说的

NCNN分配内存算法

  1. // Aligns a pointer to the specified number of bytes
  2. // ptr Aligned pointer
  3. // n Alignment size that must be a power of two
  4. template<typename _Tp>
  5. static NCNN_FORCEINLINE _Tp* alignPtr(_Tp* ptr, int n = (int)sizeof(_Tp))
  6. {
  7.     return (_Tp*)(((size_t)ptr + n - 1& -n);
  8. }
  9. // Aligns a buffer size to the specified number of bytes
  10. // The function returns the minimum number that is greater or equal to sz and is divisible by n
  11. // sz Buffer size to align
  12. // n Alignment size that must be a power of two
  13. static NCNN_FORCEINLINE size_t alignSize(size_t sz, int n)
  14. {
  15.     return (sz + n - 1& -n;
  16. }
  17. static NCNN_FORCEINLINE void* fastMalloc(size_t size)
  18. {
  19. #if _MSC_VER
  20.     return _aligned_malloc(size, NCNN_MALLOC_ALIGN);
  21. #elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17)
  22.     void* ptr = 0;
  23.     if (posix_memalign(&ptr, NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD))
  24.         ptr = 0;
  25.     return ptr;
  26. #elif __ANDROID__ && __ANDROID_API__ < 17
  27.     return memalign(NCNN_MALLOC_ALIGN, size + NCNN_MALLOC_OVERREAD);
  28. #else
  29.     unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*+ NCNN_MALLOC_ALIGN + NCNN_MALLOC_OVERREAD);
  30.     if (!udata)
  31.         return 0;
  32.     unsigned char** adata = alignPtr((unsigned char**)udata + 1, NCNN_MALLOC_ALIGN);
  33.     adata[-1= udata;
  34.     return adata;
  35. #endif
  36. }
  37. static NCNN_FORCEINLINE void fastFree(void* ptr)
  38. {
  39.     if (ptr)
  40.     {
  41. #if _MSC_VER
  42.         _aligned_free(ptr);
  43. #elif (defined(__unix__) || defined(__APPLE__)) && _POSIX_C_SOURCE >= 200112L || (__ANDROID__ && __ANDROID_API__ >= 17)
  44.         free(ptr);
  45. #elif __ANDROID__ && __ANDROID_API__ < 17
  46.         free(ptr);
  47. #else
  48.         unsigned char* udata = ((unsigned char**)ptr)[-1];
  49.         free(udata);
  50. #endif
  51.     }
  52. }

函数alighPtr 分配指针
函数alighSize 分配内存
函数fastMalloc 快速分配内存

难点3

为什么有udata之后还有adata?udata是怎么分配字节的?

  1. unsigned char*udata =(unsigned char*)malloc (size+sizeof(void*)+MALLOC_ALIGN)
  2. unsigned char**adata=alignPtr((unsigned char**)udata+1,MALLOC_ALIGN);

这里的udata分配 size以外还给了一个指针sizeof(void*) 等于8字节,buffer MALLOC_ALIGN对齐用,保存原始地址 + 对齐。

adata分配了+1,这里1用于记录结尾指针 用于free时候用。adata[-1] = udata, 就是保存最开始分配内存的头指针。

难点4

为什么用** 双重指针? adata为什么强转**

  1. // 采用类比的方式解释 
  2. unsigned char *= new char[5]; 
  3. // a + 1 表示从a指针指向的地址走了1个字节, 为啥是1个字节 
  4. // 因为unsigned char *a前面是unsigned char, unsigned char是1个字节 
  5. unsigned char** b = (unsigned char** )a;
  6.  // 同理, b + 1 表示从b指针指向的地址走了8个字节, 为啥是8个字节
  7.  // 因为unsigned char **b前面是unsigned char*, unsigned char*8个字节 

unsigned char*是个指针类型, 指针类型占8字节的大小,而如果用unsigned char*,分配只有1个字节,造成不对齐。 指针的加减 可以看做去掉一个*, 然后看前面的类型占多少字节。

所以 (unsigned char**)udata + 1 表示udata指向的类型为unsigned char*(是一个指针类型占8字节), 再加一, 即udata从指向的地址往前走了8个字节,达到对齐的目的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/703220
推荐阅读
相关标签
  

闽ICP备14008679号