C++中内存分配有关的问题整理

C程序内存模型

图示

在这里插入图片描述

组成

  • 文本段(text):文本段主要存储的是编译链接完成后的机器指令
  • 初始化数据区:包含已经初始化的全局变量和静态变量,当然可以再细分为只读和可读写的初始化数据区,该区域的数据有:
static int i = 10;
int i = 10;	// 全局变量(定义在任何函数体之外)
  • 未初始化数据区:也被称为bss(block started by symbol),该区域的内容是那些初始化为0或这没有显式初始化的变量存储的地方。例如:
static int i;
int j;	// 全局变量(定义在任何函数体之外)
  • 堆(heap):从低地址向高地址增长,malloc分配的空间即是从堆申请的空间,可以通过brk和sbrk系统调用来调整堆空间的大小。
  • 栈(stack):栈从高地址往低地址增长,增长方向与堆相反,当栈指针遇到堆指针时,说明可供分配的内存空间被耗尽。栈空间中包含的主要是栈帧,一次函数调用过程可以看成如下几部分组成:
    • 记录函数返回的地址以及上一个调用者的环境(各种寄存器的值)
    • 在栈空间上为该函数所需要的局部变量分配空间

Example

以下的实验结果,个人在类UNIX系统(Ubuntu,Centos)上都没有测试出来,使用的编译器是最新的gcc(当前日期2020-4-13),但是在windows上测试出来,使用的编译器是MinGw的gcc。因此实验结果照搬了原博客的实验结果

使用size命令简单测试
# include <stdio.h>

int main()
{
  return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960        248          8       1216        4c0    memory-layout
测试一个全局未初始化变量的存储位置
# include <stdio.h>

int global; // 预期会存储在bss区域
int main() 
{
  return 0;
}
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
 960        248         12       1220        4c4    memory-layout
测试一个静态未初始化变量的存储位置
#include <stdio.h> 
  
int global; /* Uninitialized variable stored in bss*/
  
int main(void) 
{ 
    static int i; /* Uninitialized static variable stored in bss */
    return 0; 
} 
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
 960        248         16       1224        4c8    memory-layout
测试一个静态初始化变量的存储位置
#include <stdio.h> 

int global; /* Uninitialized variable stored in bss*/

int main(void) 
{ 
	static int i = 100; /* Initialized static variable stored in DS*/
	return 0; 
} 
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960         252         12       1224        4c8    memory-layout
测试一个全局初始化变量的存储位置
#include <stdio.h> 

int global = 10; /* initialized global variable stored in DS*/

int main(void) 
{ 
	static int i = 100; /* Initialized static variable stored in DS*/
	return 0; 
} 
[narendra@CentOS]$ gcc memory-layout.c -o memory-layout
[narendra@CentOS]$ size memory-layout
text       data        bss        dec        hex    filename
960         256          8       1224        4c8    memory-layout

C++中new与operator new的区别

new关键字

当你使用new关键字创建一个对象时,new关键字所作的工作包括两部分:

  1. 使用operator new从堆空间(自由存储)分配内存空间
  2. 调用相关的构造函数来初始化内存
测试
#include<iostream> 
using namespace std; 
class car 
{ 
    string name; 
    int num; 
  
    public: 
        car(string a, int n) 
        { 
            cout << "Constructor called" << endl; 
            this ->name = a; 
            this ->num = n; 
        } 
  
        void enter() 
        { 
            cin>>name; 
            cin>>num; 
        } 
  
        void display() 
        { 
            cout << "Name: " << name << endl; 
            cout << "Num: " << num << endl; 
        } 
}; 
  
int main() 
{ 
    // Using new keyword 
    car *p = new car("Honda", 2017); 
    p->display(); 
} 
输出
Constructor called
Name: Honda
Num: 2017

operator new

operator new是一个用来分配原始内存的函数,在概念上与malloc()相似

  • 是一种默认从对上分配内存的机制
  • 仅分配内存空间而不负责初始化
  • 可以被全局重载或为某个特定类重载
测试
#include<iostream> 
#include<stdlib.h> 
  
using namespace std; 
  
class car 
{ 
    string name; 
    int num; 
  
    public: 
  
        car(string a, int n) 
        { 
            cout << "Constructor called" << endl; 
            this->name = a; 
            this->num = n; 
        } 
  
        void display() 
        {  
            cout << "Name: " << name << endl; 
            cout << "Num: " << num << endl; 
        } 
  
        void *operator new(size_t size) 
        { 
            cout << "new operator overloaded" << endl; 
            void *p = malloc(size); 
            return p; 
        } 
  
        void operator delete(void *ptr) 
        { 
            cout << "delete operator overloaded" << endl; 
            free(ptr); 
        } 
}; 
  
int main() 
{ 
    car *p = new car("HYUNDAI", 2012); 
    p->display(); 
    delete p; 
} 
输出
new operator overloaded
Constructor called
Name:HYUNDAI
Num:2012
delete operator overloaded

总结

  1. 操作符/关键字 vs 函数
  2. new会隐式调用operator new
  3. operator new可以被重载

C++中new与malloc的区别

自由存储区

new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。

那么自由存储区是否能够是堆(问题等价于new是否能在堆上动态分配内存),这取决于operator new 的实现细节。自由存储区不仅可以是堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存。

  • new不仅为新建对象分配了空间,而且调用了构造函数,例子见上文
  • new是一个关键字,malloc是一个函数
  • new返回新建对象的起始地址,malloc仅仅返回void*类型的内存空间起始地址
  • 调用失败时,new抛出bad_alloc异常,而malloc返回NULL指针
  • new分配内存的空间来自自由存储区(free store),而malloc从堆分配空间
  • new/operator new可以被重载,而malloc不行
  • new分配空间时只需传入类型由编译器计算空间,而malloc需要手动计算所需空间的大小

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值