【基】C/C++(Liunx)基本内存分区



C++中内存的五大区域

栈、(内存映射段)自由存储段、堆、(数据段)全局/静态存储区、(代码段)常量存储区

在这里插入图片描述

1.堆区

由程序员分配和释放,若不释放,程序结束时由会由OS回收

  • 堆仅存在动态分配,没有静态分配的堆,所以在申请空间之后,在使用完后最好甚至必须手动对其进行释放,以避免内存泄漏

    • 堆不手动free在如服务器等长期运行的项目中往往存在极大危害,因为在运行过程中申请的空间不断增多未释放,且程序不结束也不会强制释放空间 ,最终会导致系统崩溃
  • 基本的malloc/realloc/free 函数维护了一套内部的堆数据结构。当程序使用这些函数去获得新的内存空间时,这套函数首先试图从内部存储空间中寻找可用的内存空间,如果没有可以使用的内存空间,则试图利用系统调用来动态增加程序数据段的内存大小,新分配得到的空间首先被组织进内部堆中去,然后再以适当的形式返回给调用者。当程序释放分配的内存空间时,这片内存空间被返回内部堆结构中,可能会被适当的处理(比如和其他空闲空间合并成更大的空闲空间),以更适合下一次内存分配申请。


2.自由存储区

该概念由C++引入,除去该区域即C中的内存分区

  • 其在形式上与堆十分相似,由new与delete手动进行内存申请与释放;
    需要注意的是,其在某些时刻几乎可以等同于堆,而有时与其存在又有所不同,本文在结尾进行讨论

“Note that while the default global new and delete might be implemented in terms of malloc and free by a particular compiler, the heap is not the same as free store and memory allocated in one area cannot be safely deallocated in the other.” --Herb Sutter《exceptional C++》


3.栈

由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等

  • 栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
  • 以下举例,栈上局部变量s分配的内存空间在离开作用域后已经被销毁,此时无法再使用s的地址对其原本指向的内容进行相关操作
char* f()
{
//s数组存放于栈上
char s[4] = {'1','2','3','0'};
return s; //返回s数组的地址,但程序运行完s数组就被释放了
}
int main()
{
char *s;
s = f();
printf ("%s", s); //打印出来乱码。因为s所指向地址已经没有数据
}
  • 但值得一提的是,指针和数组在指向字符串时,还存在较大的区别,关于C/C++中数组与指针指向字符串的特性不同处的分析具体可以看看这篇博客http://t.csdn.cn/pTOPZ

  • 由此我们不难理解,对于返回值为指针类型的函数,除非其指针的地址指向静态区或常量区或堆区,否则都会其打印值都会是随机值

  • 注意:不是要求指针存储在静态区/常量区/堆区,局部指针变量除static修饰,其余指针都存储在栈上,必须的是指针指向内容存在静态区/常量区/堆区,其指向内容不会自动销毁,外部通过同一地址仍能调用

PS:对于 char* arr = “hello world”; //字符常量 该行代码c++中无法直接赋值,因为const char*->char*权限放大;但c中允许如此赋值

//指针指向内容存在常量区/静态区
char* test() 
{
	  char* arr = "hello world"; //字符常量 c++中无法直接赋值,因为const char*->char*权限放大;但c中允许如此赋值
	    //static char arr[] = "hello world!";
	 return arr;
	
}

void  test_() 
{
		 char* s = test();
	   printf("s = %s\n", s);
	
}

 int main()
 {
	     test_();
	     return 0;
	
}
——————————————————————————————————————————————————————————————————————————————————————————————
//指针指向对象存在堆区
  char *getstring()
  {
      char *p;
      p =char*malloc(100);
      strcpy(p, "hello");
  
      return  p;
  }
  
 void test()
 {
     char *ret = getstring();
     printf("%s\n", ret);
     free(ret);
     ret = NULL;
 }
 
 int main()
 {
     test();
     return 0;
 }

4.全局/静态存储区

存储全局变量、静态变量,全局区的数据在程序结束后由OS释放

  • 没什么疑惑点的点,存储全局变量、static修饰的所有变量、const修饰的全局变量;
    在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

  • 其中BSS存储未初始化变量,DATA存储已初始化变量


5.(代码段)常量区

用以存储可执行代码的二进制代码与只读常量,在程序结束后由OS释放


6.堆与自由存储区的关系

表面上似乎明显的区别在于:malloc在堆上分配的内存块,使用free释放内存,而new所申请的内存则是在自由存储区上,使用delete来释放。
但再进一步思考,大部分编译器new与delete的底层默认实现方式还是malloc和free,由此看来似乎堆和自由存储区又没有区别了,或者说自由存储区是基于堆实现的?

但是C++还存在operator重载的语法,基于此,程序员可以通过operator new/delete用自己希望的方式来实现,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。

  • 《exceptional C++》中如此描述

在这里插入图片描述

  • 自由存储区(free store)是C++两个动态内存区域之一,使用new和delete来予以分配和释放。在自由存储区(free store)中,对象的生存周期可以比存放它的内存区的生存周期短;这也就是说,我们可以获得一片内存区而不用马上对其进行初始化;同时,在对象被销毁之后,也不用马上收回其占用的内存区。在对象被销毁而其占用的内存区还未被收回的这段时间内,我们可以通过void*型的指针访问这片区域,但是其原始对象的非静态成员以及成员函数(即使我们知道了它们的地址)都不能被访问或者操纵。
  • 堆(heap)区是另一个动态存储区域,使用malloc、free以及他们的变形体来进行分配和回收。要注意,虽然在特定的编译器里缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,但是堆(heap)与自由存储区(free store)是不同的——在某一个区域内被分配的内存不能在另一个区域内被安全的回收。堆(heap)中被分配的内存一般用于对类对象进行placement-new的构造和explicit的析构。堆中对象的生存周期与自由存储区(free store)中的类似。

实际上在C++标准草案中关于这两种区域是否有联系的问题一直很谨慎地没有给予详细说明,而且特定情况下new和delete是按照malloc和free来实现,但这两种内存区域的访问与运作方式不完全同,所以也不应该被完全当成一样的东西来使用。

参考

《exceptional C++》关于heap和free store的论述
C/C++中程序内存区域划分大总结

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在Linux上配置VS Code的C/C++环境,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了g++(GCC的C++编译器)、gcc(GCC的C编译器)和gdb(GNU调试器)。您可以使用以下命令进行安装: ``` sudo apt-get update sudo apt-get install build-essential ``` 2. 在VS Code中,您可以使用快捷键`Ctrl + Shift + P`打开命令面板,然后搜索`Configure Default Build Task`来选择编译器。根据您的需求,选择适合的编译器进行配置。根据引用所示,您可以尝试使用第一个或第二个编译器来运行`.cpp`文件。 3. 安装必需的插件。根据引用所示,以下是一些常用的插件推荐: - C/C++插件:提供了C/C++语言的语法高亮、自动补全等功能。 - Code Runner插件:可以直接在VS Code中运行您的代码。 - Snippets插件:提供了一些常用的C/C++代码片段,方便您编写代码。 - EPITECH C/C Headers插件:为C/C++文件添加头部信息,包括作者、创建和修改日期等。 - File Templates插件:提供了文件模板,可以自定义添加文件模板。 - GBKtoUTF8插件:将GBK编码的文件转换为UTF-8编码。 - Include Autocomplete插件:可以自动补全头文件的路径。 - One Dark Pro插件:可以选择一个好看的VS Code主题。 这样,您就可以在Linux上成功配置VS Code的C/C++环境了。请根据您的需求选择适合的编译器和插件,并根据需要安装相应的软件包和插件。希望对您有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值