C++浅析程序中内存的分布

C++之程序的内存分布

最近在复习C++相关的知识,整理一下。

C++的存储区主要有以下几类:

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

堆区:就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉, 那么在程序结束后,操作系统会自动回收。只new不delete会造成内存泄漏。

全局/静态存储区:全局变量和静态变量(static修饰的变量)是存储在同一块内存区域的。以前C语言还区分初始化的和未初始化的全局变量,将这两类分别存储在不同的区域,现在在C++里这两者已经不做区分了。

常量存储区:就是常量字符串或者const修饰的变量,该区域的变量不允许修改。

代码区(text):存放程序代码块的地方。

这里通过一个例子来分别看一看这些不同区域的变量。

栈区

    int bb = 1;              // 栈区变量 stack
    char s[] = "abc";       // 栈地址变量
    int *p2 = NULL;         // 栈地址变量

将以上变量的地址分别打印

(lldb) p &bb
(int *) $0 = 0x00000003040cf224
(lldb) p &s
(char (*)[4]) $1 = 0x00000003040cf220
(lldb) p &p2
(int **) $2 = 0x00000003040cf218
(lldb)

可以看到这几个存储在栈区的变量是挨着存储,且地址依次从高到低变化。

堆区:

    int *ph = new int(10);       // ph在栈区,指向堆(heap)区变量 (地址增长)
    int *ph2 = new int(20);      // 堆(heap)区变量

分别打印指针的地址和指针指向的地址的值

(lldb) p &ph
(int **) $0 = 0x00000003040cf1f0   // 指针的地址,在栈区
(lldb) p &ph2
(int **) $1 = 0x00000003040cf1e8    // 指针的地址,在栈区
(lldb) p ph
(int *) $2 = 0x0000000108e20db0        // 指针指向的地址,在堆区
(lldb) p ph2
(int *) $3 = 0x0000000108e20900        // 指针指向的地址,在堆区

从上面的例子可以看到,指针本身存储在栈区,其地址相邻且从高到低变化。

指针指向的地址在另一块区域,该区域称为堆区,该区域的地址是从低到高变化的。但是并不具有相邻的特点。

全局/静态存储区

int globleA = 0;        // 全局初始化区
int *pPoint;               // 全局未初始化区 默认为0,指针为NULL
int main(int argc, const char * argv[]) {
    static int c = 0;       // 全局(静态)初始化区 (和全局变量是一样的)
   	return 0;
}

打印出地址和结果:

(lldb) p &globleA
(int *) $0 = 0x00000001000080d8            // 全局/静态变量区
(lldb) p &pPoint
(int **) $1 = 0x00000001000080e0        // 全局/静态变量区
(lldb) p &c
(int *) $2 = 0x00000001000080d4        // 全局静态变量区
(lldb) p pPoint
(int *) $3 = 0x0000000000000000        // 未初始化的值为NULL

常量区

char *p3 = "123456";    // p3在栈区,但是它指向的变量在常量区(无法改变), 指针可以跨区域访问

(lldb) p p3
(char *) $3 = 0x0000000100003f43 "123456"  // 常量区
(lldb) p &p3
(char **) $4 = 0x00000003040cf210        // 栈区

代码区

就是代码存放的地方。

下面用一张图片总结:

到此这篇关于C++浅析程序中内存的分布的文章就介绍到这了,更多相关C++内存分布内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++对象内存分布详解(包括字节对齐和虚函数表)

    1.C++对象的内存分布和虚函数表: C++对象的内存分布和虚函数表注意,对象中保存的是虚函数表指针,而不是虚函数表,虚函数表在编译阶段就已经生成,同类的不同对象中的虚函数指针指向同一个虚函数表,不同类对象的虚函数指针指向不同虚函数表. 2.何时进行动态绑定: (1)每个类对象在被构造时不用去关心是否有其他类从自己派生,也不需要关心自己是否从其他类派生,只要按照一个统一的流程:在自身的构造函数执行之前把自己所属类(即当前构造函数所属的类)的虚函数表的地址绑定到当前对象上(一般是保存在对象内存空间

  • C++ 类中有虚函数(虚函数表)时 内存分布详解

    虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table.在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承.覆盖的问题,保证其容真实反应实际的函数.这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数. 这里我们着重看一下这张虚函数表.C++的编译器应该是

  • C++内存分布及用法

    目录 一.内存基础 1.内存分布 2.栈区与堆区的区别 二.内存分配 1.内存分配方式 2.new的用法 3.delete用法 4.new与malloc的区别 5.内存泄漏 三.内存拓展 1.内存概念 2.虚拟内存 四.思考 1.代码中的b属于栈区还是堆区? 一.内存基础 1.内存分布 通过下面一张图看看C++的内存分布: 栈区:由编译器自动分配与释放,存放为程序运行时函数分配的局部变量.函数参数:栈内存分配运算内置于处理器的指令集中,效率很高,但是分配内存的容量有限: 堆区:由new.mall

  • 解析C++类内存分布

    工欲善其事,必先利其器,我们先用好Visual Studio工具,像下面这样一步一步来: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存布局,如果写上/d1 reportSingleClassLayoutXXX(XXX为类名),则只会打出指定类XXX的内存布局.近期的VS版本都支持这样配置. 下面可以定义一个类,像下面这样: class Base { int a; int b; public: void Com

  • 浅谈C++对象的内存分布和虚函数表

    c++中一个类中无非有四种成员:静态数据成员和非静态数据成员,静态函数和非静态函数. 1.非静态数据成员被放在每一个对象体内作为对象专有的数据成员. 2.静态数据成员被提取出来放在程序的静态数据区内,为该类所有对象共享,因此只存在一份. 3.静态和非静态成员函数最终都被提取出来放在程序的代码段中并为该类所有对象共享,因此每一个成员函数也只能存在一份代码实体.在c++中类的成员函数都是保存在静态存储区中的 ,那静态函数也是保存在静态存储区中的,他们都是在类中保存同一个惫份. 因此,构成对象本身的只

  • C++虚函数表与类的内存分布深入分析理解

    目录 不可定义为虚函数的函数 将析构函数定义为虚函数的作用 虚函数表原理 继承关系中虚函数表结构 多重继承的虚函数表 多态调用原理 对齐和补齐规则 为什么要有对齐和补齐 资源链接 不可定义为虚函数的函数 类的静态函数和构造函数不可以定义为虚函数: 静态函数的目的是通过类名+函数名访问类的static变量,或者通过对象调用staic函数实现对static成员变量的读写,要求内存中只有一份数据.而虚函数在子类中重写,并且通过多态机制实现动态调用,在内存中需要保存不同的重写版本. 构造函数的作用是构造

  • C++浅析程序中内存的分布

    C++之程序的内存分布 最近在复习C++相关的知识,整理一下. C++的存储区主要有以下几类: 栈区:就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区.里面的变量通常是局部变量.函数参数等. 堆区:就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉, 那么在程序结束后,操作系统会自动回收.只new不delete会造成内存泄漏. 全局/静态存储区:全局变量和静态变量(static修饰的变量

  • 深入理解JavaScript程序中内存泄漏

    垃圾回收解放了我们,它让我们可将精力集中在应用程序逻辑(而不是内存管理)上.但是,垃圾收集并不神奇.了解它的工作原理,以及如何使它保留本应在很久以前释放的内存,就可以实现更快更可靠的应用程序.在本文中,学习一种定位 JavaScript 应用程序中内存泄漏的系统方法.几种常见的泄漏模式,以及解决这些泄漏的适当方法. 一.简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许

  • 浅析Golang中的内存逃逸

    目录 什么是内存逃逸分析 为什么需要逃逸分析 如果变量放错了位置会怎样 内存逃逸场景 return 局部变量的指针 interface{} 动态类型 栈空间不足 闭包 性能 最后 什么是内存逃逸分析 内存逃逸分析是go的编译器在编译期间,根据变量的类型和作用域,确定变量是堆上还是栈上 简单说就是编译器在编译期间,对代码进行分析,确定变量分配内存的位置.如果变量需要分配在堆上,则称作内存逃逸了. 为什么需要逃逸分析 因为go语言是自动自动内存管理的,也就是有GC的.开发者在写代码的时候不需要关心考

  • 浅析JAVA中的内存结构、重载、this与继承

    一.对象在JVM的内存结构 JAVA内存管理由JVM来管理. 1)堆,所有new出来的对象(包括成员变量) 2)栈,所有局部变量(包括方法的参数) 3)方法区,class字节码文件(包括方法,静态数据) 1.引用变量指向null时,会发生空指针异常 public class student { int age; String name; public student(int age,String name){ this.age=age; this.name=name; } public stat

  • C程序中Ubuntu、stm32的内存分配问题

    目录 一.内存分区概念介绍 1.1.C/C++编译程序的内存占用 1.2.栈和堆.全局/静态存储区和常量存储区的对比 1.3.图片说明  二.C语言编程论证 1.1.Ubuntu测试代码实现  1.2.STM32验证代码实现 1.3.keil下stm32存储观察 三.总结 四.参考资料 一.内存分区概念介绍 1.1.C/C++编译程序的内存占用 1.栈区(stack) 由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) 一般由程序员分配

  • 微信小程序中的生命周期与生命周期函数浅析介绍

    目录 一.生命周期 概念 分类 二.生命周期函数 概念 作用 分类 三.总结 一.生命周期 概念 生命周期(Life Cycle)是指一个对象从创建-->运行-->销毁的整个阶段 小程序的生命周期 小程序启动,表示生命周期的开始 小程序关闭.表示生命周期的结束 中间小程序的整个运行过程就是小程序的生命周期 分类 应用生命周期 特指小程序从启动-->运行-->销毁的过程 页面生命周期 特指小程序中每个页面的加载-->渲染-->销毁的整个过程 自定义组件生命周期 组件实例被

  • C++浅析数据在内存中如何存储

    目录 一.数据类型 二.原码反码补码 三.大小端 整型提升 一.数据类型 数据类型有7种: char            字符型     short          短整型    int               整型   long            长整型   long long    更长整型   float            单精度浮点数    double        双精度浮点数 二.原码反码补码 计算机中的整数有三种2进制表示方法,即原码.反码和补码. 三种表示方法均

  • C语言程序中结构体的内存对齐详解

    目录 一.为什么存在内存对齐 二.结构体的内存对齐四规则 三.举例 一.为什么存在内存对齐 1.平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的:某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常. 2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐. 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问:而对齐的内存访问仅需要一次访问. 总的来说结构体的内存对齐是拿空间来换取时间的做法. 二.结构体的内存对齐四规则 默认情况:默认的对

  • 深入浅析python中的多进程、多线程、协程

    进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. 程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等. 每次执行程序的时候,都会完成一定的功能,比如说浏览器帮我们打开网页,为了保证其独立性,就需要一个专门的管理和控制执行程序的数据结构--进程控制块. 进程就是一个程序在一个数据集上的一次动态执行过程. 进程一般由程序.数据集.进程控

  • 浅析java中stringBuilder的用法

    String对象是不可改变的.每次使用 System.String类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间.在需要对字符串执行重复修改的情况下,与创建新的 String对象相关的系统开销可能会非常昂贵.如果要修改字符串而不创建新的对象,则可以使用System.Text.StringBuilder类.例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder类可以提升性能. 通过用一个重载的构造函数方法初始化变量,可以创建 Strin

随机推荐