首页 > 编程语言 > 详细

C++ 内存管理学习笔记

时间:2020-03-14 00:43:33      阅读:95      评论:0      收藏:0      [点我收藏+]

C++ 内存管理

C++ primitives

包含new,new[],new(),::operator new(),...
::operator new() 本质就是调用malloc
::operator delete 本质就是调用free
举个有意思的例子

#ifdef __MSC_VER
int * p4 = allocator<int>().allocate(5, (int*)0);
allocator<int>().deallocate(p4, 5);
#endif
#ifdef __BORLANDC__
int * p4 = allocator<int>().allocate(5);
allocator<int>().deallocate(p4, 5);
//显然这是通过分配器来分配内存
#endif
#ifdef __GNUC__
void* p4 = alloc::allocate(512);
alloc::deallocate(p4, 512);
#endif
//在后续的版本只能够CNUC也更新到类似与BORLANDC
void *p5 = __gnu_cxx::__pool_alloc<int>().allocate(9);
__gnu_cxx::__pool_alloc<int>().deallocate((int*)p5, 9);
//__pool_alloc内存池水

接着举个使用new 的例子
或者说是new operator的过程

Complex *pc;
Complex * pc = new Complex(1, 2);
......
delete pc;
//下述就是Complex的new operator
try{
    void * men = operator new(sizeof(Complex));
    pc = static_cast<Complex*>(men);
    pc->Complex::Complex(1, 2);
    //能不能这样写不一定
}catch(std::bad_alloc){

}

void *operator new(size_t size, const std::nothrowt&) _THROW0*()
{
    //std::nothrow设置为函数不抛出异常
    void * p;
    while((p = malloc(size)) == 0){
        _TRY_BEGIN
        if(_callnewh(size) == 0) break;
        //callnewh调用这个函数,这玩意可以被自己设定
        _CATCH(std::bad_alloc) return(0);
        _CATCH_END
    }
    return (p);
}
//delete的使用过程
pc->~Complex();
operator delete(pc);

void __cdecl operator delete(void *p)_THROW0(){
    free(p);
}

array new, array delete

Complex* pca = new Complex[3];
delete[] pca;

malloc设计申请空间会给出一个cookie
内存结构可以看侯捷的课
placement new的使用方法大概如下

new(point)constructor();

使用array new与new的内存空间布局不一样

placement new

或指new(p)
或::operator new(size_t, void *)
形式如下

#include <new>
char * buf = new char[size(Complex) * 3];
Complex * pc = new(buf)Complex(1, 2);
delete [] buf;

//经过编译器的处理如下

try{
    void * mem = operator new(sizeof(Complex), buf);
    pc = static_cast<Complex*>(men);
    pc -> Complex::Complex(1, 2);
}catch(std::bad_alloc){

}

C++应用程序,分配内存的途径

member function 可重载

//假设存在一个Foo类
Foo::operator new(size_t);
Foo::operator delete(void *);

重载::operator new / :: operator delete
overloaded function
例子如下:

void myAlloc(size_t size){
    return malloc(size);
}
void myFree(void * ptr){
    return free(ptr);
}
inline void * operator new(size_t size){
    return myAlloc(size);
}
inline void * delete delete(void * ptr){
    return myFree(ptr);
}
class Foo{
public:
    static void * operator new(size_t);
    static void * operator delete(void *, size_t);
}
void * operator new(size_t size, void * start){
    return start;
}//这个就是标准库已提供的placement new()的重载形式
void * operator new(size_t size, long extra){
    return malloc(size + extra);
}//这个是崭新的placement new
void * operator new(size_t size, long extra, char init)
{
    return malloc(size + extra);
}//这个也是一个崭新的placement new

一次malloc会多8个字节的cookie
内存池目标:

  1. 速度
  2. 空间
    写一个分配器
class Screen{
public:
    static void * operator new(size_t);
    static void operator delete(void*, size_t);
private:
    Screen* next;
    static Screen* freeStore;
    static const int screenChunk;
private:
    int i;
}
Screen* Screen::freeStore = null;
const int Screen::screenChunk = 24;
void * Screen::operator new(size_t size){
    Screen *p;
    if(!freeStore){
        size_t chunk = screenChunk * size;
        freeStrore = p = reinter_cast<Screen*>
        (new char[chunk]);
        for(; p != &freeStore[sceenChunk - 1]; ++ p){
            p -> next = p + 1;
        }
        p -> next = null;
    }
    p = freeStore;
    freeStore = freeStore -> next;
    return p;
}
void Screen::operator delete(void *p, size_t){
    (static_cast<Sreen*>(p))->next = freeStore;
    freeStore = static_cast<Screen*>(p);
    //头插法回收内存
    //其实我在这里有个疑问
    //我的问题是,如果空间不够用了呢
    //好吧,其实我是傻逼,不够了,他会对应扩容
    //然后回收的时候连接起来,这样的话,规模会越来越大
}

上述实现会多一个指针,有第二种实现
具体看侯捷课程,懒得抄
(xswl,借出来的内存不还233333)

static allocator

当你受困必须为不容的classes重写一遍几乎想通的member operatornew 跟 operator delete,应该有对应的一个类来实现
就是下述的例子,都交给static allocator来实现

class Foo{
public:
 long L;
 string str;
 static allocator myAlloc;
public:
Foo(long l):L(l){}
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);
}
}
allocate Foo::myAlloc;

偷懒真是一件神奇的事情,那么根据上述的例子,我们可以选择偷懒一波,所以引出了对应的macro for static allocator
例子如下

#define DECLARE_POOL_ALLOC() 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);
}
#define IMPLEMENT_POOL_ALLOC(class_name)allocator class_name::myAlloc;


class Foo{
    DECLARE_POOL_ALLOC()
};
IMPLEMENT_POOL_ALLOC(FOO)
//我猜等等应该要讲template

内容补充:
new handler
抛出exception之前会先调用一个可由client指定的handler
以下是new handler的形式与设定方法

typedef void(*new_handler)();
new_handler set_new_handler(new_handler p)throw();

new handler只有两个选择

  1. 让更多内存可用
  2. 调用abort()或exit()
    举个使用例子
void noMoreMemory(){
    cerr << "out of memory";
    abort();
}
set_new_handler(noMoreMemory);

std::allocator

海量小区块 会导致cookie的浪费
VC6标准allocator只是以::operator new 和 ::operator delete
完成allocate()和deallocate(),没有任何特殊的设计
BC5与VC6 allocator一样的实现效果

G2.9容器使用的分配器,不是std::allocator而是std::alloc
G4.9变化为__pool_alloc
G4.9有许多extended_allocators

C++ 内存管理学习笔记

原文:https://www.cnblogs.com/qq136155330/p/12490019.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!