“瑜珈山夜话” ----内存分配(二)

原创 2003年07月09日 11:40:00

    new/delete究竟做了些什么
   
在理解这个问题之前,我们先看一下下面的这段程序,有这么一个程序段:
       class A
       {
       public:
           A() {   cout<<"A is here!"<<endl;   }
           ~A(){   cout<<"A is dead!"<<endl;   }
       private:
           int i;
       };
       A* pA=new A;
       delete pA;
    在这个简单的程序段里面,new/delete究竟做了些什么?
    实际上,这段程序里面隐含调用了一些我们没有看到的东西,那就是:
    static void* operator new(size_t sz);
    static void  operator delete(void* p);
    值得注意的是,这两个函数都是static的,所以如果我们重载了这2个函数(我们要么不重载,要重载就要2个一起行动),也应该声明为static的,如果我们没有声明,系统也会为我们自动加上。另外,这是两个内存分配原语,要么成功,要么没有分配任何内存。
    size_t是什么东西呢?我在第一次看到这个动动的时候也是十分的困惑,毕竟以前没有见过。size_t在<cstddef>中定义,是一种无符号整数类型(不一定是int),用来保存对象的大小,这一用法是从C语言中借用过来的,现在你应该明白了吧(我学习的时候可是郁闷了好几天,没有人可以问,因为不知道有个csdn:)
    new A;实际上做了2件事:调用opeator new,在自由存储区分配一个sizeof(A)大小的内存空间;然后调用构造函数A(),在这块内存空间上类砖砌瓦,建造起我们的对象。同样对于delete,则做了相反的两件事:调用析构函数~A(),销毁对象,调用operator delete,释放内存。不过需要注意的是,new分配一块内存的时候,并没有对这块内存空间做清零等任何动作,只是拿了过来,这块内存上放的仍然是原来的数据(垃圾数据),delete的时候,也只是释放这块内存,归还给操作系统,上面的数据还在上面,所以delete pA之后,pA的值没变,他指向的那块内存的值也没有变,不过似乎有什么问题,我们看一下下面的这个程序段:
 int *p=new int(50000);
 cout<<*p<<"   "<<p<<endl;
 delete p;
 cout<<*p<<"   "<<p<<endl;
    我们可以清楚地看到,指针p存放的数据仍然是原来的地址,但是*p的内容却发生了变化,在我的机器上(win2000, VC6)始终是-572662307,不清楚这是为什么,难道系统做了什么手脚?还望高手指教。  
    在这里我们可以看到,new的工作实际上就是保证相互分离的存储分配和初始化工作能够很好的在一起工作,不过这里可能让初学者迷惑的是,我们定义了一个带有参数的new,但是我们用的时候却没有显式的去调用,而是让系统“神秘”的去提供这个参数。是的,这样做毫无疑问增加了复杂性,但是让基类获取了为一集派生类提供分配和释放服务的能力。  

    new/delete有什么好处和坏处
    从C程序员转换过来的C++程序员总是有个困惑:new/delete到底究竟和C语言里面的malloc/free比起来有什么优势?或者是一样的?
    其实,就算我不说,你也应该很清楚了,new/delete当然比malloc/free要好,要不然,为什么还引进这个东东呢?其实通过上面的分析,我们看到了new/delete实际上做了很多malloc/free没有做的事情:malloc/free只是对内存进行分配和释放;new/delete还负责完成了创建和销毁对象的任务。
    另外,new的安全性要高一些,因为他返回的就是一个所创建的对象的指针,对于malloc来说返回的则是void*,还要进行强制类型转换,显然这是一个危险的漏洞。
    最后,我们可以对new/delete重载,使内存分配按照我们的意愿进行,这样更具有灵活性,malloc则不行。
    不过,new/delete也并不是十分完美,大概最大的缺点就是效率低(针对的是缺省的分配器),原因不只是因为在自由存储区上分配(和栈上对比),具体的原因目前不是很清楚,不过在MCD上说了2个可能的原因:
    1、new只是对于堆分配器(malloc/realloc/free)的一个浅层包装,没有针对小型的内存分配做优化。
    2、缺省分配器具有通用性,它管理的是一块内存池,这样的管理往往需要消耗一些额外空间。

    各种各样的new
    一般来说,new有很多种形式,不过真的归纳起来,也就是2种:
    1、最常用的形式:
       void *operator new(std::size_t sz)    throw(std::bad_alloc);   (普通的)
       void *operator new[](std::size_t sz)  throw(std::bad_alloc);    (数组的)
       void *operator new(std::size_t sz);
       void *operator new[](std::size_t sz)
    这一种大家用得最为频繁,我就不举例子了。
    2、放置new形式:
       void *operator new(std::size_t count, void *ptr)   throw();    (普通的)
       void *operator new[](std::size_t count, void *ptr) throw();     (数组的)
    要使用这种方式,必须包含头文件<new>。这个机制引入的初始目的是为了解决2个相关的问题:
       1、把一个对象放在某个特定位置;
       2、在某个特定分配区里面分配对象;
       但是引入之后,发现这种机制远超出了简单的存储分配机制,我们可以给特定的存储位置关联任意的逻辑性值,这样一来,new就有了一种通用资源管理器的作用。同时第二个参数,也被扩展成了任意的可以识别的类型,并且配备了相应的nothrow版本:
       void* operator new(std::size_t, const std::nothrow_t&)   throw();
       void* operator new[](std::size_t, const std::nothrow_t&) throw();

    new能够返回NULL么?
    我们经常看到有很多初学者喜欢写如下代码:
    A* p=new A();
    if(p==NUL) ....
    写下这段代码的可能是受到了一些书上错误的影响,因为new A()从来就不可能返回NULL,如果在这个过程中用完了内存,那么他就会抛出bad_alloc异常,绝对不会返回NULL,如果你想让他返回null,应该用new(nothrow) A(),而不是new A()。不过从异常的观点来看,这实际上是一种倒退,我们应该尽量回避。

内存山介绍和图解析

存储器山是一种综合研究存储器层次结构的工具。它反映了存储器层次结构中不同层次的带宽。也反映了具有不同的时间局部性与空间局部性的程序的性能。通过分析存储器山的数据,还可以看出存储器系统的部分硬件参数。 ...
  • u010352695
  • u010352695
  • 2015年01月04日 22:34
  • 1118

C++/C中内存分配情况详解

 一、一个经过编译的C/C++的程序占用的内存分成以下几个部分: 1、栈区(stack): 由编译器自动分配和释放 ,存放函数的参数值、局部变量的值等,甚至函数的调用过程都是用栈来完成。其操...
  • ac540101928
  • ac540101928
  • 2016年08月31日 09:34
  • 799

Matlab预分配内存

预分配内存简介:对于for,while循环,在循环的过程中每次不断的增加数据结构的大小,影响了性能和内存的使用。重复的调整数据的大小需要Matlab花费额外的时间寻找更大的连续内存块,并且将现在的数组...
  • xuluhui123
  • xuluhui123
  • 2016年09月29日 09:58
  • 10438

谈一谈js的内存分配

因为js是一门动态语言,动态分配内存的方式让使用者运用快速便捷,却忽略了他的内存分配机制,今天我来试着理清思路。     还是那个惯例,从基础讲起,然后发散思维,由浅入深。     JavaScrip...
  • u014168594
  • u014168594
  • 2017年01月16日 10:17
  • 323

new分配内存的详细解释

new operator(C++中的new有三重含义)在申请内存的时候,首先会调用operator new 来分配内存,operator new在申请内存失败时,缺省行为是抛出异常,一旦抛出异常,而不...
  • zhouguoqionghai
  • zhouguoqionghai
  • 2015年10月02日 00:34
  • 2336

浅谈设置JVM内存分配的几个妙招

一、设置JVM内存设置 1. 设置JVM内存的参数有四个: -Xmx    Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定; ...
  • jaslou
  • jaslou
  • 2016年04月12日 22:15
  • 1424

VMware内存分配初探

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://delxu.blog.51cto.com/975660/281559 ...
  • xiaoxinyu316
  • xiaoxinyu316
  • 2015年01月10日 11:41
  • 1886

操作系统常见内存分配算法及优缺点

常见内存分配算法及优缺点如下:   (1)首次适应算法。使用该算法进行内存分配时,从空闲分区链首开始查找,直至找到一个能满足其大小需求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存分配给...
  • u012387575
  • u012387575
  • 2016年04月01日 10:30
  • 1989

Malloc是如何分配内存的?

在用户调用malloc之后,系统中发生了什么呢?
  • aganlengzi
  • aganlengzi
  • 2016年05月07日 19:15
  • 1820

Redis内存分配策略

Redis为了屏蔽不同平台间的差异,以及统计内存占用量等,对内存分配函数进行了一层封装。 redis判断系统是否使用tcmalloc或者jemalloc内存分配器或苹果系统自带的malloc,...
  • CodingMyself
  • CodingMyself
  • 2017年02月09日 17:34
  • 1640
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:“瑜珈山夜话” ----内存分配(二)
举报原因:
原因补充:

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