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

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

1.创建一个类

class Foo
{
private:
int _id; //
long _data;//
string _str;// public:
Foo():_id()
{
cout << "default ctor.this=" << this << " id=" << _id << endl;
}
Foo(int a):_id(a)
{
cout << "ctor.this=" << this << " id=" << _id << endl;
} // virtual
~Foo()
{
cout << "dtor.this=" << this << " id=" << _id << endl;
} //申请内存的函数必须是必须是静态的 调用这个函数时一般都是正在创建这个对象 所以当调用时你这个对象还不存在 所以需要声明成静态
static void* operator new(size_t size);
static void operator delete(void* pdead, size_t size);
static void* operator new[](size_t size);
static void operator delete[](void* pdead, size_t size);
};

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

    void* Foo::operator new(size_t size)//size 为将要申请的内存大小
{
Foo* p = (Foo*)malloc(size);
cout <<"operator new().sizeof()="<< size << " return=" << p <<endl;
return p; //p 为内存起始点
} void Foo::operator delete(void* pdead, size_t size)//pdead 删除点 和上面的p为同一个位置 size 为将要删除的内存大小
{
cout <<"operator delete.pdead=" << pdead << " size=" << size <<endl;
cout << endl;
free(pdead);
} void* Foo::operator new[](size_t size)
{
Foo* p = (Foo*)malloc(size);
cout <<"operator new[].size="<< size <<" return=" << p << endl;
return p;
} void Foo::operator delete[](void* pdead, size_t size)
{
cout<< "operator delete[].pdead=" << pdead << " size="<< size <<endl;
cout << endl;
free(pdead);
}

下面调用一下测试函数

    void test()
{
cout << "sizeof(Foo)="<<sizeof(Foo) << endl;
Foo* p = new Foo();
delete p; Foo* pArray = new Foo[];
delete [] pArray;
}

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

class A
{
int a;
...
int j;//共10个int型变量
}

那么这个类的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类

class Screen
{
public:
Screen(int x): i(x)
{
//todo
} int get()
{
return i;
} void* operator new(size_t);
void operator delete(void*, size_t); private:
Screen* next;//4bit
static Screen* freeStore;
static const int screenChunk;//想要创建多少组 private:
int i; //4bit
}; Screen* Screen::freeStore = ;
const int Screen::screenChunk = ;

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

void* Screen::operator new(size_t size)
{
Screen* p;
if(!freeStore)
{
//linked list是空的,所以申请一大块内存
size_t chunk = screenChunk * size; //192 Screen的内存大小为8共24组 24 * 8 = 192
freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
cout << "startPisotion: " << p << endl; //将一大块内存分割成片段,当做linked list串接起来
for(; p != &freeStore[screenChunk-]; ++p)
{
p->next = p+;
}
p->next = ;
}
p = freeStore;
freeStore = freeStore->next; return p;
} void Screen::operator delete(void* p, size_t)
{
//将delete object插回 free list前端
(static_cast<Screen*>(p)) -> next = freeStore;
freeStore = static_cast<Screen*>(p);
}

测试代码

void test()
{
cout << sizeof(Screen) << endl; size_t const N = ; Screen* p[N]; cout << "overload operator new" << endl;
for(int i=; i<N; i++)
{
p[i] = new Screen(i);
} for(int i = ; i<; i++)
{
cout << p[i] << endl;//输出每个Screen的内存起点
} for(int i=; i<N; i++)
{
delete p[i];
} cout << "glob operator new" << endl; Screen* q[N]; for(int i=; i<N; i++)
{
q[i] = ::new Screen(i);
} for(int i = ; i<; i++)
{
cout << q[i] << endl;
} for(int i=; i<N; i++)
{
::delete q[i];
}
}

测试结果

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

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

测试代码

namespace wzj03_class12_15 {

class Screen
{
public:
Screen(int x): i(x)
{
//todo
} int get()
{
return i;
} void* operator new(size_t);
void operator delete(void*, size_t); private:
Screen* next;//4bit
static Screen* freeStore;
static const int screenChunk; private:
int i; //4bit
}; Screen* Screen::freeStore = ;
const int Screen::screenChunk = ; void* Screen::operator new(size_t size)
{
Screen* p;
if(!freeStore)
{
//linked list是空的,所以申请一大块内存
size_t chunk = screenChunk * size; //192 Screen的内存大小为8共24组 24 * 8 = 192
freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
cout << "startPisotion: " << p << endl; //将一大块内存分割成片段,当做linked list串接起来
for(; p != &freeStore[screenChunk-]; ++p)
{
p->next = p+;
}
p->next = ;
}
p = freeStore;
freeStore = freeStore->next; return p;
} void Screen::operator delete(void* p, size_t)
{
//将delete object插回 free list前端
(static_cast<Screen*>(p)) -> next = freeStore;
freeStore = static_cast<Screen*>(p);
} void test()
{
cout << sizeof(Screen) << endl; size_t const N = ; Screen* p[N]; cout << "overload operator new" << endl;
for(int i=; i<N; i++)
{
p[i] = new Screen(i);
} for(int i = ; i<; i++)
{
cout << p[i] << endl;
} for(int i=; i<N; i++)
{
delete p[i];
} cout << "glob operator new" << endl; Screen* q[N]; for(int i=; i<N; i++)
{
q[i] = new Screen(i);
} for(int i = ; i<; i++)
{
cout << q[i] << endl;
} for(int i=; i<N; i++)
{
delete q[i];
}
} }

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

namespace wzj03_class12_15_1 {
class myAllocator
{
private:
struct obj
{
struct obj* next;
}; public:
void* allocate(size_t);
void deallocate(void*, size_t);
private:
obj* freeStore = nullptr;
const int CHUNK = ;
}; void myAllocator::deallocate(void* p, size_t size)
{
cout << "myAllocator::deallocate" << "size: " << size <<endl;
((obj*)p)->next = freeStore;
freeStore = (obj*)p;
} void* myAllocator::allocate(size_t size)
{
cout << "myAllocator::allocate" << "size: " << size <<endl;
obj* p;
if(!freeStore)
{
size_t chunk = CHUNK * size;
freeStore = p = (obj*)malloc(chunk); for(int i=; i<(CHUNK-); ++i)
{
p->next = (obj*)((char*)p + size);
p = p->next;
} p->next = nullptr;
}
p= freeStore;
freeStore = freeStore -> next; return p;
} class Foo
{
public:
long L;
string str;
static myAllocator myAlloc;
public:
Foo(long l): L(l)
{
//todo
} static void* operator new(size_t size)
{
return myAlloc.allocate(size);
} static void operator delete(void* pdead, size_t size)
{
return myAlloc.deallocate(pdead, size);
}
};
myAllocator Foo::myAlloc; void test()
{
cout << sizeof(Foo) << endl; size_t const N = ; Foo* p[N]; cout << "overload operator new" << endl;
for(int i=; i<N; i++)
{
p[i] = new Foo(i);
} for(int i = ; i<N; i++)
{
cout << p[i] << endl;
} for(int i=; i<N; i++)
{
delete p[i];
} cout << "glob operator new" << endl; Foo* q[N]; for(int i=; i<N; i++)
{
q[i] = ::new Foo(i);
} for(int i = ; i<N; i++)
{
cout << q[i] << endl;
} for(int i=; i<N; i++)
{
::delete q[i];
}
} }

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. ajax post 参数说明

  2. attr返回被选元素的属性值

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 到底二级域名和一级域名哪个更利于SEO

    到底二级域名和一级域名哪个更利于SEO呢?本文是从百度官方转载详细的介绍:二级域名和一级域名的区别,请各位认真阅读. 二级域名和子域名的区别可以通过以下3点来解读: 一,二级域名的特点 搜索引擎往往将 ...

  4. POJ 3295 Tautology(构造法)

    http://poj.org/problem?id=3295 题意: 判断表达式是否为永真式. 思路: 把每种情况都枚举一下. #include<iostream> #include< ...

  5. ASP.NET MVC 中使用Ckeditor4.5 编辑器

    一.在项目中添加Ckeditor4.5.11 (1) 新建 ASP.NET MVC5项目,解压缩ckeditor_4.5.11_standard.zip,在VS2015的解决方案资源管理器中将得到的“ ...

  6. java23种设计模式之一: 策略模式

    由于最近在研究学习设计模式,我会用自己的理解方式来表述对设计模式的学习和认识,通过最常用.好记的案例来记住和使用设计模式,希望对设计代码方面有所提高和改进. 一.应用背景     在软件开发中常常遇到 ...

  7. 03_ExeZZ.cpp

    1.静态加载 DLL : #pragma comment(lib, "DllZZ.lib") __declspec(dllimport) void __stdcall AA(); ...

  8. BN层

    论文名字:Batch Normalization: Accelerating Deep Network Training by  Reducing Internal Covariate Shift 论 ...

  9. Codeforces 431C - k-Tree

    431C - k-Tree 思路:dp. dp[i][j][s] 如果s为1,表示第i层长度为j且至少包含一段>=d的距离的路径数 如果s为0,表示第i层长度为j且不包含一段>=d的距离的 ...

  10. _proto_和prototype区别

    推荐一篇阅读:http://cometosay.com/2016/08/31/js-proto.html es中创建对象的方法 (1)对象字面量的方式 (2)new 的方式 (3)ES5中的`Obje ...