当前位置: 首页 > news >正文

C++ 内存分配

什么是内存

一个C/C++编译的程序占用内存分为以下几个部分:

栈区(stack):由 编译器自动分配和释放,存放的是 运行时函数分配的局部变量,函数参数,返回数据,返回地址等参数,其操作类似于数据结构中的栈。

堆区(heap):一般 由程序员手动分配,如果程序员没有释放,程序结束时可能由os回收,其分配类似于链表。

全局区(静态区static):存放全局变量,静态数据,常量。程序结束后由系统释放,全局区分为已初始化全局区(data)和未初始化全局区(bss)。

常量区(文字常量区):存放常量字符串,程序结束后由系统释放

代码区:存放函数体(类成员函数和全局区)的二进制代码
.
.

三种内存分配方式:

一.从静态存储区分配内存
从静态存储区分配的内存在 程序编译的时候就已经被分配完毕了,这块内存在程序的整个运行期间都会存在(例如全局变量,static变量)

二.在栈上创建内存空间
在执行函数时, 函数内局部变量的存储单元可以在栈上创建,函数执行结束的时候,这些内存单元会自动被释放,栈内存分配运算内置于处理器的指令集,效率高,但是 分配的内存容量有限

三.在堆上分配内存(动态内存分配)🌟
在堆上分配内存亦被称为动态分配内存,程序在运行的时候使用malloc或者new申请 任意大小的内存,程序员自己负责在何时使用free和delete进行动态分配的内存的释放。 动态内存的生命周期是由程序员决定的,而且动态内存的申请和释放的使用过程非常灵活,but!如果在堆上分配了空间,则必须对堆上分配的内存进行回收,因为系统是无权对堆上的内存进行管理的,若只是申请了动态内存却不对内存进行释放,程序将会出现内存泄漏,且 频繁的分配和释放不同大小的堆空间将产生内存碎片。
.
.

内存分配的简易示意图:

在这里插入图片描述
静态全局数据区:存放全局数据和静态数据
代码段:存放可执行代码和只读常量
堆区:存放动态开辟的变量
栈区:非静态局部变量、函数参数,返回值等

堆和栈的区别

管理方式不同:栈由编译器自动申请和释放空间,堆需要程序员手动申请和释放空间。

空间大小不同:栈的空间有限,32位平台下,VC6下默认为1M,而堆最大可以达到4G。

能否产生碎片: 栈和数据结构中的栈原理相同,在弹出一个元素之前,上一个元素已经弹出了,所以不会产生碎片,但如果不停的进行动态内存的申请和释放则会积累很多内存碎片。

生长方向的不同:堆的生长方向是向上的,也就是向着内存地址增加的方向,而栈刚好是相反的,栈是向着内存减小的方向生长的(因为栈的空间十分有限,所以栈是从上限往栈的下限生长的)

分配的方式不同:堆都是动态分配的,没有静态能进行分配的堆。而栈有静态分配和动态分配两种分配方式。静态分配是编译器完成的,比如局部变量的分配,动态分配在C++中由new函数进行分配。请注意:栈的动态分配和堆的是不同的,栈的动态分配由编译器进行释放,无需使用delete进行释放。

分配的效率不同:栈的效率比堆要高很多,因为栈是机器系统提供的数据结构,计算机在底层提供了栈的支持,分配专门的寄存器来存放栈的地址,压栈和出栈都有相应的指令,因此栈在分配的效率上是一定比堆上快的。而堆是由库函数提供的,机制很复杂,库函数会按照一定的算法进行搜索内存,因此比较慢。

栈中内存的申请和释放:
通常来说,一个线程上的栈内存是有限的,通常为8MB左右(大小取决于运行环境),栈上的内存通常是由编译器自动管理的。当在栈上分配一个新的变量时,或进入一个函数时,栈的指针会向下移动(下压栈),相当于在栈上分配了一块内存。我们把变量分配在栈上,也就是利用了栈上的内存空间,当这个变量的生命周期结束的时候,栈的指针会上移,相当于回收了此块内存。

正是由于栈上的内存和分配和回收均是由编译器自动完成控制的,所以在上是不会发生内存泄漏的,只会发生栈 溢 出的情况(Stack Overflow),也就是分配的空间超过了规定的栈大小。

堆中内存的申请和释放:
堆中的内存是由程序直接控制的,程序可以通过[new/delete]来分配和回收内存,如果程序中通过[new]手动分配了一块内存,但忘记使用[delete]来回收内存,便会发生内存泄漏。


静态全局变量(static),全局变量,静态局部变量(static),局部变量的区别:

静态全局变量和全局变量的区别:
1.静态全局变量和全局变量 都属于常量区
2.静态全局区 只在本文件中有效,别的文件如果向调用该变量,是调用不了的,且 全局变量在别的文件中还可以调用
3.如果别的文件中定义了一个该全局变量相同的的变量名,是会出错的。

静态局部变量和局部变量的区别:
1.静态局部变量是属于常量区的,而函数内部的局部变量属于栈区。
2.静态局部变量在该函数调用结束的时候,不会销毁,而是随着整个程序的结束而结束,静态局部变量不能被此函数外的函数调用。局部变量也是随着该函数的结束而结束的。
3.如果定义这两个变量的时候没有赋初始值,那么静态局部变量会自动的定义为0,而局部变量就是一个随机的值(一般的编译器会强制要求局部变量必须进行赋初值 而静态局部变量是否赋初值则不做强制性要求)。
4.静态局部变量在编译期间只赋值一次,以后每次调用函数时,不再赋值,而是直接调用上次的函数调用结束时的值。而局部变量在调用期间,每调用一次,便会对这个局部变量进行重新赋值

在这里插入图片描述

总结:🎯
全局变量:可以被本程序所有对象或函数引用.
静态全局变量:是在全局变量声明前加上一个static关键字,使该变量只能在这个源文件可用.
局部变量:只能被函数内部引用,而无法被其他的对象或函数引用.
静态局部变量:通常放在函数内部,只能在函数内部被调用,只进行一次初始化,每次执行函数时保持上一次执行的值.

来自https://blog.csdn.net/cherrydreamsover/article/details/81627855
来自https://blog.csdn.net/cherrydreamsover/article/details/81627855
来自 C++动态内存管理项目

相关文章:

  • C++ 动态内存管理
  • IOS学习资源
  • C++ 从函数或方法返回动态内存(函数指针与指针函数)
  • PHP实现多web服务器共享SESSION数据-session数据写入mysql数据库
  • C++ 副本构造器
  • C++常识之——C++中堆和栈的区别,自由存储区、全局/静态存储区和常量存储区...
  • C++ 高级强制类型转换
  • thinkphp的一些类库
  • C++ 指针和引用
  • 9月24号忘记
  • C++ 避免内存泄漏
  • [转]SQL Server DBCC用法大全
  • C++ 命名空间和模块化编程
  • FG终于投出去了~
  • 资源仓库
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • Git的一些常用操作
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • JAVA多线程机制解析-volatilesynchronized
  • npx命令介绍
  • Python打包系统简单入门
  • React 快速上手 - 07 前端路由 react-router
  • React中的“虫洞”——Context
  • 初识 webpack
  • 计算机在识别图像时“看到”了什么?
  • 开发基于以太坊智能合约的DApp
  • 开源SQL-on-Hadoop系统一览
  • 算法-插入排序
  • 赢得Docker挑战最佳实践
  • 自定义函数
  • linux 淘宝开源监控工具tsar
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • #{} 和 ${}区别
  • (C语言)共用体union的用法举例
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (ZT)薛涌:谈贫说富
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (循环依赖问题)学习spring的第九天
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)shell调试方法
  • (转)程序员技术练级攻略
  • .chm格式文件如何阅读
  • .mysql secret在哪_MySQL如何使用索引
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .net FrameWork简介,数组,枚举
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .Net 应用中使用dot trace进行性能诊断
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • .Net转Java自学之路—基础巩固篇十三(集合)