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关键字所作的工作包括两部分:
- 使用operator new从堆空间(自由存储)分配内存空间
- 调用相关的构造函数来初始化内存
测试
#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
总结
- 操作符/关键字 vs 函数
- new会隐式调用operator new
- 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需要手动计算所需空间的大小