记录学习的点点滴滴,参考侯捷<<C++内存管理>>

我们先重载一下C++的几个内存管理函数 operator new, operator new[], operator delete, operator delete[]

1.创建一个类

  1. class Foo
  2. {
  3. private:
  4. int _id; //
  5. long _data;//
  6. string _str;//
  7.  
  8. public:
  9. Foo():_id()
  10. {
  11. cout << "default ctor.this=" << this << " id=" << _id << endl;
  12. }
  13. Foo(int a):_id(a)
  14. {
  15. cout << "ctor.this=" << this << " id=" << _id << endl;
  16. }
  17.  
  18. // virtual
  19. ~Foo()
  20. {
  21. cout << "dtor.this=" << this << " id=" << _id << endl;
  22. }
  23.  
  24. //申请内存的函数必须是必须是静态的 调用这个函数时一般都是正在创建这个对象 所以当调用时你这个对象还不存在 所以需要声明成静态
  25. static void* operator new(size_t size);
  26. static void operator delete(void* pdead, size_t size);
  27. static void* operator new[](size_t size);
  28. static void operator delete[](void* pdead, size_t size);
  29. };

上一节提到过operator new 和 operator delete的实现是基于malloc()和free() 这边也直接在函数内声明这两个函数

  1. void* Foo::operator new(size_t size)//size 为将要申请的内存大小
  2. {
  3. Foo* p = (Foo*)malloc(size);
  4. cout <<"operator new().sizeof()="<< size << " return=" << p <<endl;
  5. return p; //p 为内存起始点
  6. }
  7.  
  8. void Foo::operator delete(void* pdead, size_t size)//pdead 删除点 和上面的p为同一个位置 size 为将要删除的内存大小
  9. {
  10. cout <<"operator delete.pdead=" << pdead << " size=" << size <<endl;
  11. cout << endl;
  12. free(pdead);
  13. }
  14.  
  15. void* Foo::operator new[](size_t size)
  16. {
  17. Foo* p = (Foo*)malloc(size);
  18. cout <<"operator new[].size="<< size <<" return=" << p << endl;
  19. return p;
  20. }
  21.  
  22. void Foo::operator delete[](void* pdead, size_t size)
  23. {
  24. cout<< "operator delete[].pdead=" << pdead << " size="<< size <<endl;
  25. cout << endl;
  26. free(pdead);
  27. }

下面调用一下测试函数

  1. void test()
  2. {
  3. cout << "sizeof(Foo)="<<sizeof(Foo) << endl;
  4. Foo* p = new Foo();
  5. delete p;
  6.  
  7. Foo* pArray = new Foo[];
  8. delete [] pArray;
  9. }

下图示侯捷在<<C++内存管理>> 在VC6上的内存管理图片

  1. class A
  2. {
  3. int a;
  4. ...
  5. int j;//共10个int型变量
  6. }

那么这个类的Debug版实际内存应该是下图这种

这个图片分为 白色的上下cookie 上下cookie占8字节 10个灰色的data数据占40字节 12字节的补全字节 和一个橙色的4字节空位,

上面我用的是Qt的编译器

看上面log的第7行 "operator new[].size=64  return = 0x8714c0" 起始内存点在0x8714c0.但是构造函数的内存起点是0x8714c4

那么这4个字节就是上图白色部分的cookie,它的内存分配应该是下图所示

那么当我们每创建一组这样的数据,那就会有上下两个cookie(8字节),那么当我们创建多组数据的话就会有很多组cookie,那么就会占用一些花销

有一种方法减少这种内存的花销,那就是内存池操作


内存池

先说一下内存池的优点

1.减少malloc的使用,提高运行效率

2.可以指定对齐方式

3.减少内存碎片,减少cookie

创建一个Screen类

  1. class Screen
  2. {
  3. public:
  4. Screen(int x): i(x)
  5. {
  6. //todo
  7. }
  8.  
  9. int get()
  10. {
  11. return i;
  12. }
  13.  
  14. void* operator new(size_t);
  15. void operator delete(void*, size_t);
  16.  
  17. private:
  18. Screen* next;//4bit
  19. static Screen* freeStore;
  20. static const int screenChunk;//想要创建多少组
  21.  
  22. private:
  23. int i; //4bit
  24. };
  25.  
  26. Screen* Screen::freeStore = ;
  27. const int Screen::screenChunk = ;

重载operator new(创建内存池)和operator delete

  1. void* Screen::operator new(size_t size)
  2. {
  3. Screen* p;
  4. if(!freeStore)
  5. {
  6. //linked list是空的,所以申请一大块内存
  7. size_t chunk = screenChunk * size; //192 Screen的内存大小为8共24组 24 * 8 = 192
  8. freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
  9. cout << "startPisotion: " << p << endl;
  10.  
  11. //将一大块内存分割成片段,当做linked list串接起来
  12. for(; p != &freeStore[screenChunk-]; ++p)
  13. {
  14. p->next = p+;
  15. }
  16. p->next = ;
  17. }
  18. p = freeStore;
  19. freeStore = freeStore->next;
  20.  
  21. return p;
  22. }
  23.  
  24. void Screen::operator delete(void* p, size_t)
  25. {
  26. //将delete object插回 free list前端
  27. (static_cast<Screen*>(p)) -> next = freeStore;
  28. freeStore = static_cast<Screen*>(p);
  29. }

测试代码

  1. void test()
  2. {
  3. cout << sizeof(Screen) << endl;
  4.  
  5. size_t const N = ;
  6.  
  7. Screen* p[N];
  8.  
  9. cout << "overload operator new" << endl;
  10. for(int i=; i<N; i++)
  11. {
  12. p[i] = new Screen(i);
  13. }
  14.  
  15. for(int i = ; i<; i++)
  16. {
  17. cout << p[i] << endl;//输出每个Screen的内存起点
  18. }
  19.  
  20. for(int i=; i<N; i++)
  21. {
  22. delete p[i];
  23. }
  24.  
  25. cout << "glob operator new" << endl;
  26.  
  27. Screen* q[N];
  28.  
  29. for(int i=; i<N; i++)
  30. {
  31. q[i] = ::new Screen(i);
  32. }
  33.  
  34. for(int i = ; i<; i++)
  35. {
  36. cout << q[i] << endl;
  37. }
  38.  
  39. for(int i=; i<N; i++)
  40. {
  41. ::delete q[i];
  42. }
  43. }

测试结果

你会发现调用全局的和调用重载的函数结果差别会很大

全局operator new的默认对齐方式是16字节对齐而且会发现没有了cookie,而且减少了malloc得使用提高使用效率

测试代码

  1. namespace wzj03_class12_15 {
  2.  
  3. class Screen
  4. {
  5. public:
  6. Screen(int x): i(x)
  7. {
  8. //todo
  9. }
  10.  
  11. int get()
  12. {
  13. return i;
  14. }
  15.  
  16. void* operator new(size_t);
  17. void operator delete(void*, size_t);
  18.  
  19. private:
  20. Screen* next;//4bit
  21. static Screen* freeStore;
  22. static const int screenChunk;
  23.  
  24. private:
  25. int i; //4bit
  26. };
  27.  
  28. Screen* Screen::freeStore = ;
  29. const int Screen::screenChunk = ;
  30.  
  31. void* Screen::operator new(size_t size)
  32. {
  33. Screen* p;
  34. if(!freeStore)
  35. {
  36. //linked list是空的,所以申请一大块内存
  37. size_t chunk = screenChunk * size; //192 Screen的内存大小为8共24组 24 * 8 = 192
  38. freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
  39. cout << "startPisotion: " << p << endl;
  40.  
  41. //将一大块内存分割成片段,当做linked list串接起来
  42. for(; p != &freeStore[screenChunk-]; ++p)
  43. {
  44. p->next = p+;
  45. }
  46. p->next = ;
  47. }
  48. p = freeStore;
  49. freeStore = freeStore->next;
  50.  
  51. return p;
  52. }
  53.  
  54. void Screen::operator delete(void* p, size_t)
  55. {
  56. //将delete object插回 free list前端
  57. (static_cast<Screen*>(p)) -> next = freeStore;
  58. freeStore = static_cast<Screen*>(p);
  59. }
  60.  
  61. void test()
  62. {
  63. cout << sizeof(Screen) << endl;
  64.  
  65. size_t const N = ;
  66.  
  67. Screen* p[N];
  68.  
  69. cout << "overload operator new" << endl;
  70. for(int i=; i<N; i++)
  71. {
  72. p[i] = new Screen(i);
  73. }
  74.  
  75. for(int i = ; i<; i++)
  76. {
  77. cout << p[i] << endl;
  78. }
  79.  
  80. for(int i=; i<N; i++)
  81. {
  82. delete p[i];
  83. }
  84.  
  85. cout << "glob operator new" << endl;
  86.  
  87. Screen* q[N];
  88.  
  89. for(int i=; i<N; i++)
  90. {
  91. q[i] = new Screen(i);
  92. }
  93.  
  94. for(int i = ; i<; i++)
  95. {
  96. cout << q[i] << endl;
  97. }
  98.  
  99. for(int i=; i<N; i++)
  100. {
  101. delete q[i];
  102. }
  103. }
  104.  
  105. }

这段代码是封装了一个小型内存池

  1. namespace wzj03_class12_15_1 {
  2. class myAllocator
  3. {
  4. private:
  5. struct obj
  6. {
  7. struct obj* next;
  8. };
  9.  
  10. public:
  11. void* allocate(size_t);
  12. void deallocate(void*, size_t);
  13. private:
  14. obj* freeStore = nullptr;
  15. const int CHUNK = ;
  16. };
  17.  
  18. void myAllocator::deallocate(void* p, size_t size)
  19. {
  20. cout << "myAllocator::deallocate" << "size: " << size <<endl;
  21. ((obj*)p)->next = freeStore;
  22. freeStore = (obj*)p;
  23. }
  24.  
  25. void* myAllocator::allocate(size_t size)
  26. {
  27. cout << "myAllocator::allocate" << "size: " << size <<endl;
  28. obj* p;
  29. if(!freeStore)
  30. {
  31. size_t chunk = CHUNK * size;
  32. freeStore = p = (obj*)malloc(chunk);
  33.  
  34. for(int i=; i<(CHUNK-); ++i)
  35. {
  36. p->next = (obj*)((char*)p + size);
  37. p = p->next;
  38. }
  39.  
  40. p->next = nullptr;
  41. }
  42. p= freeStore;
  43. freeStore = freeStore -> next;
  44.  
  45. return p;
  46. }
  47.  
  48. class Foo
  49. {
  50. public:
  51. long L;
  52. string str;
  53. static myAllocator myAlloc;
  54. public:
  55. Foo(long l): L(l)
  56. {
  57. //todo
  58. }
  59.  
  60. static void* operator new(size_t size)
  61. {
  62. return myAlloc.allocate(size);
  63. }
  64.  
  65. static void operator delete(void* pdead, size_t size)
  66. {
  67. return myAlloc.deallocate(pdead, size);
  68. }
  69. };
  70. myAllocator Foo::myAlloc;
  71.  
  72. void test()
  73. {
  74. cout << sizeof(Foo) << endl;
  75.  
  76. size_t const N = ;
  77.  
  78. Foo* p[N];
  79.  
  80. cout << "overload operator new" << endl;
  81. for(int i=; i<N; i++)
  82. {
  83. p[i] = new Foo(i);
  84. }
  85.  
  86. for(int i = ; i<N; i++)
  87. {
  88. cout << p[i] << endl;
  89. }
  90.  
  91. for(int i=; i<N; i++)
  92. {
  93. delete p[i];
  94. }
  95.  
  96. cout << "glob operator new" << endl;
  97.  
  98. Foo* q[N];
  99.  
  100. for(int i=; i<N; i++)
  101. {
  102. q[i] = ::new Foo(i);
  103. }
  104.  
  105. for(int i = ; i<N; i++)
  106. {
  107. cout << q[i] << endl;
  108. }
  109.  
  110. for(int i=; i<N; i++)
  111. {
  112. ::delete q[i];
  113. }
  114. }
  115.  
  116. }

C++内存管理-重载内存管理函数的更多相关文章

  1. (转)从内存管 理、内存泄漏、内存回收探讨C++内存管理

    http://www.cr173.com/html/18898_all.html 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟 ...

  2. davlik虚拟机内存管理之一——内存分配

    转载自http://www.miui.com/thread-74715-1-1.html dalvik虚拟机是Google在Android平台上的Java虚拟机的实现,内存管理是dalvik虚拟机中的 ...

  3. C++ Primer : 第十二章 : 动态内存之动态内存管理(new和delete)

    C++语言定义了两个运算符来分配和释放动态内存:运算符new分配内存,运算符delete释放new分配的内存. 运算符new和delete 使用new动态分配和初始化对象 在自由空间分配的内存是无名的 ...

  4. Delphi的内存管理及内存泄露问题 FastMM4

    这几天因为一个程序长时间运行出现比较严重的内存泄露问题,开始关注了一下内存管理方面的东西,以前也注意内存管理,创建了对象及时释放,但总有忘了处理的情况. 在Delphi中没有自动回收机制,所以一定要及 ...

  5. Java的内存管理与内存泄露

    作为Internet最流行的编程语言之一,Java现正非常流行.我们的网络应用程序就主要采用Java语言开发,大体上分为客户端.服务器和数据库三个层次.在进入测试过程中,我们发现有一个程序模块系统内存 ...

  6. android 管理Bitmap内存 - 开发文档翻译

    由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接   Managing Bitmap Memory 管理Bitmap内存 In additi ...

  7. [内存管理]连续内存分配器(CMA)概述

    作者:Younger Liu, 本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可. 原文地址:http://lwn.net/Articles/396657/ 1 ...

  8. C语言(记录)——内存相关_2:内存的编址与管理

    本文是基于嵌入式的C语言 --------------------------------------------------------------------------------------- ...

  9. kmalloc分配物理内存与高端内存映射--Linux内存管理(十八)

    1 前景回顾 1.1 内核映射区 尽管vmalloc函数族可用于从高端内存域向内核映射页帧(这些在内核空间中通常是无法直接看到的), 但这并不是这些函数的实际用途. 重要的是强调以下事实 : 内核提供 ...

随机推荐

  1. [JVM] - 继10进制的java.lang.Object查看之后

    cmd清除命令:cls 之后查阅了其它博客,发现这位大神同样也在做JVM,并且我很希望用它的10进制转16进制类来测试一下该解析的10进制是否对应着Object的16进制呢? 这位大神的10进制转16 ...

  2. hdu 5381 The sum of gcd 莫队+预处理

    The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) P ...

  3. flask报错No module named 'flask.ext'

    解决: from flask.ext.httpauth import HTTPBasicAuth 改为 from flask_httpauth import HTTPBasicAuth 提示Modul ...

  4. ubuntu 14.04 安装redis5.0.3

    redis下载地址:http://download.redis.io/releases/ 新建Redis目录,下载Redis 安装包: mkdir rediscd rediswget http://d ...

  5. Python 以指定宽度格式化输出

    当对一组数据输出的时候,我们有时需要输出以指定宽度,来使数据更清晰.这时我们可以用format来进行约束 mat = "{:20}\t{:28}\t{:32}" print(mat ...

  6. c++ primer plus 第六章 课后题答案

    #include <iostream> #include <cctype> using namespace std; int main() { char in_put; do ...

  7. C#将集合和Json格式互相转换的几种方式

    1.使用微软自带的System.Web.Extensions.dll转换,该DLL文件一般存在于如下路径:c:\Program Files\Reference Assemblies\Microsoft ...

  8. IntelliJ Idea工具使用

    以前一直用eclipse/myeclipse开发,最近因为需要学习了intelliJ Idea工具,感觉真的挺好用的..好用的东西就要掌握加以利用,特写一篇简单的总结(只写大体). 一,什么是Inte ...

  9. python 小练习12

    给你一个整数数列a1,a2,a3,...,an,请你修改(不能删除,只能修改)最少的数字,使得数列严格单调递增. 数列存储在列表L中,你可以直接使用L,L的长度小于100000. 注意:必须保证修改后 ...

  10. httpclient妙用一 httpclient作为客户端调用soap webservice(转)

    前面有一篇使用HttpClient调用带参数的post接口方法,这里找到一篇使用HttpClient调用Soap协议接口的方式. 原文地址:httpclient妙用一 httpclient作为客户端调 ...