Solmyr和Zero的故事 —— 内存,最后一块

原创 2002年07月11日 09:43:00
   “Shit!又死机了。我已经在这平台上工作了一个月了。可死机的次数比我在这个月里被女孩甩的次数还多。为什么?还不是这该死的平台,为什么掌上系统的内存就和愿意和我说话的女孩一样少?Solmyr抱怨道。

 

“兄弟,怎么了。”Zero问。

 

      Zero是我们这组的主程序员,他懂得很多,人长的也帅,很讨女孩子的欢心。甚至连美工组的Lili(长得比孙燕姿还好看)也暗恋他。Solmyr一边想,一边说,老大,你看,又死机了。为什么我每次用动态内存超过10次,就crash了呢?

 

“我知道你原来是Java程序员,也许到现在,你还念念不忘那GC (垃圾收集机制,我说还不如叫上帝也哭泣-God  Cry),可你要知道,你现在是在用C++编程,重要的是效率。

 

      效率,我……”忽然,Solmyr觉得嘴角边似乎有液体流过。那是Solmyr的口水。每次提到效率,Solmyr总要流口水,就像看到漂亮MM,Solmyr要喷鼻血一样。

 

      C++中,关于动态内存的是new and delete。”

 

“我知道,”Solmyr急于表现自己,想证明自己对C++并不是一无所知,我正在读Scott Meyer的More Effective C++。在C++中,new operatorC++内建的行为。任何人(也许除了Bjarne Stroustrup)都无法改变。new operator先调用一个名为operator new的函数动态申请内存。标准模式就像这样:

 

      void* operator new(size_t size);

      然后在传回的void*指针上进行构造的行为。而delete operator则先析构对象,然后调用名为operator delete的函数,标准形式就像这样:

      void operator delete(void* pToDeAlloc)

// GotW中说即使在指针参数后加上size_t size,仍然是标准形式。

// size_t size的作用是检查所要卸除的内存是否是期望的大小,如果在类层次中定义的话,只要基类是virtual destructor,那么size可以// 确保是正确大小。

placement new……。”

 

      唔,说得不错,有进步。关于placement new/delete,先知Meyer[1]有详细的论述。原来的placement new仅仅是这样:

      void* operator new(size_t, void* pMem) { return pMem; }

‘ 随着时间过去,任何‘要求额外引数’的 operator new 版本,也都渐渐采用 placement new 这个术语。事实上这个术语已经被铭记於 C++ 标准规格中。因此,当 C++ 程序员谈到所谓的 placement new 函数,他们所谈的可能是上述那个需要额外一个 void* 参数,用以指出物件置于何处的版本,但也可能是指那些所需参数比单一而必要之 size_t 引数更多的任何 operator new 版本,包括上述函数,也包括其他参数更多operator new 函数。’——引自[1]

 

现在我们来考虑一个问题,如果在operator new结束申请内存后,构造函数抛出了异常,那么已经申请的内存谁来回收,答案当然是编译器。因为整个new operator还未结束。所以你无法获得控制权。如果你对operator new/delete进行了重载,那么编译器会调用那个operator  delete呢?由于不同的operator new可能通过不同的方法获得内存,而让不知道怎样分配的operator delete去释放内存显然是不负责任的。所以编译器假定哪个operator deleteoperator new有相同的参数(除了size_t sizevoid* pDeAlloc),那么那个operator delete便知道operator new怎样获得内存。构造函数抛出异常后,也会调用与operator new相同参数的operator delete来释放内存。”

 

      “那么,我该怎么解决现在的问题呢?”

“别那么急,已经下午五点了。该回家了,别让人以为程序员是夜游神。回家看看Effective C++第二部分和GotW9, GotW10。明天再说吧。”

 

第二天一早,Solmyr啃着大饼走进了办公室,看到Guru Zero早已姿势优雅地坐在电脑前收发Email,不禁自惭形秽,连忙放下手中的大饼,跑去和Zero说:“老大,昨天晚上,我挑灯夜读,总结出两点:

1.     如果你写了一个operator new,请对应写一个operator delete

2.     不要delete不是自己new来的内存。

“嗯,不错,怎么我看上去,就象是Effective C++中的条款呢?你有没有自己想过关于placement delete的问题?”

placement delete有什么问题吗?”Solmyr一脸茫然的问道。

“你有没有试过把一块用placement new申请得到的内存用placement delete卸除掉呢?不妨你现在试试看。”

 

只见Solmyr跑到一台电脑前,两手如飞在键盘上敲击,可是我们能听到的只有他的唉声叹气和编译器的哇哇大叫。Solmyr实在是没办法,只能向Zero求教。Zero喝了一口咖啡,说道:“我们平时写的那些要求额外参数的operator delete只有在构造函数抛出异常时,才会被编译器自动调用,而我们是不可能手工调用到任何带有额外参数的delete的,为什么没有一个内建的‘placement delete’来与‘placement new’相匹配的原因在于没有办法保证它被正确使用,在C++类型系统中,无法推断一个指针从哪里获得它指向的内存,可能是指向heap,也可能是stack。所以……”

 

“所以当我们确实知道一个指针它是怎么获得它所指向的内存时,我们可以这样:

template<class T> void destroy(T* p, Arena& a)

        {

                if (p) {

                        p->~T();      // explicit destructor call

                        a.deallocate(p);

                }

        }

这样,就不会有资源泄漏了。”[2]

“可是我怎么解决我那稀有的内存的问题呢?”

“标准库中的allocatorboost中的pool可以解决内存管理的问题,不必每次调用operator new,从而少了一些开销,不过早上我刚收到客户的mail,他们说准备在他们的设备上再加12MB的内存。”

“……”Solmyr郁闷中。

 

      [1]Object Counting in C++ CUJ 1998.4 中文译文 陈崴 http://www.jjhou.com/(程序员杂志:2001.8 杂志上少了placement new and placement delete)

      [2] Bjarne Stroustrup's C++ Style and Technique FAQ  Is there a "placement delete"?

CUDA零拷贝内存(zerocopy memory)

为了实现CPU与GPU内存的共享,cuda采用了零拷贝内存,它值固定内存的一种,当然,也就是实际存储空间实在cpu上。 零拷贝内存的延迟高,在进行频繁的读写操作时尽量少用,否则会大大降低性能。 /...
  • Rong_Toa
  • Rong_Toa
  • 2017年11月29日 16:07
  • 130

C指针与malloc,free

首先什么是指针:指针用来存放变量的地址,也就是操作操作内存。C语言中定义一个指针变量存储内存的地址,它是一个32位无符号整数的值。 1、如何初始化一个指针 int *pbuff1; 和 int *...
  • mndlyt
  • mndlyt
  • 2014年03月13日 11:25
  • 1259

Nginx源码分析(1)之——共享内存的配置、分配及初始化

Nginx源码分析(1)之——共享内存的配置、分配及初始化
  • hnudlz
  • hnudlz
  • 2016年03月23日 16:25
  • 1291

C 内存分配方式

堆和栈的区别 一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类...
  • sxsdjkk
  • sxsdjkk
  • 2014年07月08日 14:08
  • 233

kmalloc - 内存申请

原型: void *kmalloc(size_t size, int flags) 功能: 在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc、vmalloc,或者用g...
  • qq_25077833
  • qq_25077833
  • 2016年12月04日 16:39
  • 435

利用D3D抓取GPU数据

microsoft 提供的D3D SDK是用来进行3D建模和利用GPU运算的一组接口的集合, D3D SDK至少有两个优点: 1、提供了一种3D建模的构架,程序员可以很容易的用这种构架来建...
  • seamanj
  • seamanj
  • 2013年05月03日 05:47
  • 1087

malloc 从哪里得到的内存空间

在计算机高级编程语言中,C 语言相对来说是一种低级语言,从某种意义上讲,C 语言就是现代的“汇编语言”。说 C 语言低级很大程度上是因为 C 程序员需要手动管理存储,具体反应在公认最难最容易出错的指针...
  • polar9527
  • polar9527
  • 2014年08月02日 00:49
  • 426

再谈 内存对齐补齐--提高cpu检索周期效率

首先我们先看看下面的C语言的结构体: [cpp] view plain copy   typedef struct MemAlign   {   ...
  • vevenlcf
  • vevenlcf
  • 2016年06月30日 15:13
  • 555

指向数组的指针

指向数组的指针变量成为数组指针变量。一个数组是由连续的一块内存单元组成的。数组名就是这块连续内存单元的首地址。该实例我们实现了使用数组的指针引用数组,利用数组名以及下标引用数组等。其中,使用数组的指针...
  • hongbochen1223
  • hongbochen1223
  • 2015年05月10日 00:18
  • 925

理解进程内存

目录[-] #从虚拟内存到物理内存 top:进程统计 显而易见的列 共享内存 数据 SWAP pmap:详细映射信息 基本内容 ## 扩展内容 更多? 原文地...
  • zdy0_2004
  • zdy0_2004
  • 2016年03月05日 21:04
  • 1220
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Solmyr和Zero的故事 —— 内存,最后一块
举报原因:
原因补充:

(最多只允许输入30个字)