C++对象模型(2)-- 进程内存空间布局

C++内存管理(一)---进程地址空间和物理内存区别 C++内存管理 首先强调的一点是:每个进程都认为自己独立的享有着计算机的内存 首先虚拟内存与物理内存的区别 虚拟内存:程序运行时,会进行一系列的操作,(本章只进行虚拟内存的讲解) 进程会构建自己的虚拟地址空间(进程地址空间),该地址空间所有进程都独立的享有一份,如果是32位机器,则会创建2^32(4G)大小的地址空间 ,如果是64位机器,可以创建2^64大小的地址空间(目前所有的程序都没有这么大)... 阅读详情

在前面Base类的对象模型中,有base对象实例,虚函数表,静态变量和函数等,这些信息在内存中都有各自的保存位置。了解进程的内存空间布局,比如内存空间分成几大块,各种不同的数据分别保存在内存空间的哪个位置,对深入理解对象模型是非常有帮助的。

1、进程内存空间布局
当把一个可执行文件加载到内存后,就变成了一个进程。
通常进程的内存地址空间可分为以下几个部分:栈、堆、BSS段、数据段、代码段。

1.1 各内存段说明
(1)栈(stack):栈用于存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。
(2)堆(heap):堆用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。若程序员不释放,则会发生内存泄漏。
(3)bss段(bss segment):通常是指用来存放程序中未初始化的全局变量的一块内存区域。bss段属于静态内存分配。
(4)data段(data segment):通常是指用来存放程序中已初始化的全局变量的一块内存区域。data段属于静态内存分配。
(5)代码段(code segment/text segment):通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

1.2 代码段和数据段的区别
(1)代码段和data段都在可执行文件中,由系统从可执行文件中加载,其内容由程序初始化;而bss段不在可执行文件中,其内容由系统初始化。
(2)bss段并不给该段的数据分配空间,只是记录数据所需空间的大小。而数据段会给数据分配空间,数据保存在目标文件中。

2、内存空间布局的验证

2.1 示例程序的进程空间布局

当分别声明下面2行语句时,其进程空间内存布局是不同的。

Base* pb = nullptr;  
Base* pb = new Base();  

代码验证:

int main() {
    Base* pb = NULL;
    printf("print()的地址:%p\n", &(Base::print));
    printf("print_s()的地址:%p\n", &(Base::print_s));
    printf("Base::base_s的地址:%p\n", &(Base::base_s));

    pb->print();
    pb->print_s();
    std::cout << pb->base_s << std::endl;
}

估计有读者会感到奇怪,这个pb是NULL,应该报空指针错误啊。

但这个代码是能够正确执行的。而且在编译完成后,多次运行输出的print()、print_s()、base_s地址都是相同的。

为什么呢?

因为一个可执行文件,它的全局变量、全局函数、类静态成员变量等的地址值在编译完成时就已经确定好的,不会发生改变。

成员函数print()、静态函数print_s()和静态变量base_s是跟着类走的,成员函数、静态函数存在代码段,静态变量存在数据段。

下面我们再在main()里添加2行代码:

pb->print_v();
std::cout << pb->base_i << std::endl;

发现这2行代码报错了,我这里用vs2019是提示:pb 是 nullptr。

为什么呢?

非静态成员变量、虚函数指针才会放到对象中。pb是个NULL指针,没指向任何对象,所以在调用其非静态变量base_i、虚函数print_v()时会报nullptr错误。

2.2 变量的存储位置

int bss_1; // 未初始化的全局变量 - bss段
int bss_2 = 0; // 初始化为0的全局变量 - bss段
int data_1 = 1; // 初始化非0的全局变量 - data段

int main() {
    static int bss_3; // 未初始化的静态局部变量 - bss段
    static int bss_4 = 0; // 初始化为0静态局部变量 - bss段
    static int data_2 = 1; // 初始化非0静态局部变量,data段

    printf(" ------ bss段地址 ------\n");
    printf(" bss_1 = %p\n", &bss_1);
    printf(" bss_2 = %p\n", &bss_2);
    printf(" bss_3 = %p\n", &bss_3);
    printf(" bss_4 = %p\n\n", &bss_4);

    printf(" ------ data段地址 ------\n");
    printf(" data_1 = %p\n", &data_1);
    printf(" data_2 = %p\n", &data_2);

    return 0;
}

从下面的运行结果可以看到,bss段和data段里数据的存放顺序跟声明顺序是一致的,且data段的地址在bss段的下面。

linux进程中的内存分布 进程空间分布概述 对于一个进程,其空间分布如下图所示: 程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。 初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据。 未初始化过的数据(BSS):在程序运行初未对变量进行初始化的数据。 栈 (Stack):存储局部、临时变量,函数调用时,存储函数的返回指针,用于控制函数的调用和返回。在程序块开始时自动分配内存,结束时自动释放内存,其操作方式类似于数据结构中的栈。 堆 (Heap):存储动态内存分配,需要程序员手工. 阅读详情

相关推荐

进程的地址空间布局&C++进程内存分区

每个进程都运行在属于自己的内存沙盘中。这个沙盘就是虚拟地址空间(Virtual Address Space) ????在32位模式下它是一个4GB的内存地址块。➡分为内核空间,用户空间 Linux的虚拟地址空间范围为0~4G,Linux内核将这4G字节的空间分为两部分, 将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF)供内核使用,称为“内核空间”。 而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF)供各个进程使用,称为“用户空间。 在Linux系统中, 内

Wonder Wall 1591

嵌入式必备基础一

一、进程与线程 1.1 进程和线程的概念 1.1.1 什么是进程、线程,各自有什么优点 概念: 进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发; 线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发;线程是操作系统可识别的最小执行和调度单位。每个线程都独自占用一个虚拟处理器:独自的寄存器组,指令计数器和处理器状态。每个线程完成不同的任务,但是共享同一地址空间(也就是同样的动态内存,映射文件,目标代码等等),打开的文件队列和

usstmiracle的博客 1250

C++对象模型探索视频课程

目录: ┣━━1-1 c++对象模型探索课程详细介绍.mp4 ┣━━2-7 程序转化语义.mp4 ┣━━2-10 成员初始化列表说.mp4 ┣━━2-2 对象结构的发展和演化.mp4 ┣━━2-3 this指针调整.mp4 ┣━━2-4 分析obj目标文件,构造函数语义.mp4 ┣━━2-5 构造函数语义续.mp4 ┣━━2-6 拷贝构造函数语义.mp4 ┣━━2-1 类对象所占用的空间.mp4 ...

weixin_46240865的博客 774

数据段、代码段、堆栈段、BSS段的区别

5个数据段        进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等。不过进程对这些内存的管理方式因内存用途 不一而不尽相同,有些内存是事先静态分配和统一回收的,而有些却是按需要动态分配和回收的。对任何一个普通进程来讲,它都会涉及到5种不同的数据段。 Linux进程的五个段 下面我们来简单归纳一下进程对应的内存空间中所包含的

我思故我在 4664

Linux C/C++ or 嵌入式面试之《多进程多线程编程系列》(13) 请你描述下进程虚拟内存空间布局

对于这个问题,面试官可能拿出一张白纸,让你尝试画出linux下进程的虚拟内存空间布局,然后=再让你简述下每个分区的作用,可能会挑几个重点分区,例如堆区、栈区来进行深入展开,考察你对堆栈的理解等等。 文章目录1 内核空间2 栈(stack)3 内存映射段(mmap)4 堆(heap)5 BSS段6 数据段(Data)7 代码段(text)8 保留区问题提问 在多任务操作系统中,每个进程都运行在属于自己的内存沙盘中。这个沙盘就是虚拟地址空间(Virtual Address Space),在32位模式下它是一个4

二进制君 2694

从Oracle迁移数据到Hadoop

目标:把Oracle 下的数据文件迁移到 Hadoop , 数据表都是上亿条,每个数据表的空间都超过100G。 关键是建立数据文件是UTF8格式,这样数据中的汉字在Hadoop 里显示才正常。 平台:CentOS 6.10 工具:Python 2.7 cx_Oracle 库 Oracle10.2.0.4.0 Hadoop 2.7.2-transwarp-5.2.1 1. 查看表...

预则立 4236

进程的空间模型及其代码验证

进程的空间模型以及用C语言代码验证

maderfaker的博客 516

告别I2C和SPI:用FPGA驱动DS18B20,一根线搞定温度采集(附Verilog代码)

本文详细介绍了如何利用FPGA通过单总线协议(One-Wire)驱动DS18B20温度传感器,仅用一根数据线实现高效温度采集。内容涵盖协议解析、Verilog代码实现及调试技巧,帮助开发者节省IO资源并提升系统性能。

weixin_42696271的博客 389

(C++对象模型):进程内存空间布局

进程内存空间布局 当运行一个可执行文件时,操作系统就会把这个可执行文件加载到内存,此时进程有一个虚拟的地址空间(内存空间) 演示代码 #include <iostream> #include <time.h > #include <stdio.h> using namespace std; int *ptest = new int(120); int g1; int g2; int g3 = 12; int g4 = 32; int g5; int g6

baidu_41388533的博客 331

华为路由器 VRRP主备配置

3、R3 出口路由器。

一直被模仿,从未被超越 5586

避开这些坑!用Python ReportLab生成PDF时字体处理与中文排版的5个关键技巧

本文针对Python ReportLab库在PDF自动化生成中常见的中文排版难题,提供了五个关键技巧。内容涵盖字体注册的稳健策略、段落样式的精细控制、表格内中文的换行对齐、页面布局管理以及性能优化,旨在帮助开发者彻底解决中文乱码、排版错位等问题,生成专业美观的PDF文档。

weixin_29250403的博客 624

C++ 数据语义学——进程内存空间布局

当把一个可执行文件加载到内存后,就变成了一个进程。

慢慢记录,慢慢更新。 680

光电振荡器(OEO):从原理到应用,解锁高频微波信号新纪元

本文深入解析了光电振荡器(OEO)的核心原理与前沿应用。OEO通过巧妙的光-电-光转换机制,利用光学谐振腔产生高频、高纯度、低相位噪声的微波信号,有效突破了传统电子电路的频率瓶颈。文章详细拆解了其工作流程,并探讨了在雷达系统、高速光通信及精密测量等领域的硬核应用价值。

weixin_29231027的博客 366

【Linux】进程地址空间

本篇文章先讲述了C/C++中的普遍认知,例如空间布局图、堆栈相对而生和栈区申请与访问相关知识,然后详细阐述了进程地址空间的核心概念,包括地址的深入理解、进程地址空间的本质以及区域划分的必要性。进程地址空间通过将内存空间有序化,有效提升了进程访问内存的安全性与效率,实现了进程管理与内存管理在操作系统层面的解耦,并确保了各进程间的独立性。希望本篇文章对大家有所帮助。

是阿建吖! 2301

QCPColorMap实现瀑布图

QCPColorMap实现真正的瀑布图

pf1873252141的博客 5271

uniapp - 微信支付报错 requestPayment:fail:HBuilder mainifest.json中配置的支付appid和生成订单使用的appid不一致,如果是HB调试请在线打包

uni-app,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,微信支付,报错,errMsg,requestPayment:fail:HBuildermainifest.json中配置的支付appid和生成订单使用的appid不一致,如果是HB调试请在线打包,http://ask.dcloud.net.cn/article/282,已经都检查了还是报错,如何解决这个问题,还是不行,错误,苹果微信支付报错,安卓app微信支付出错,打包,在线打包也不行,本地打包,支

🏆 前端领域优质创作者 3500

C++对象模型学习笔记十六: 进程内存空间布局

知识点: 不同的数据在内存中会有不同的 保存时机,保存位置 当运行一个可执行文件时,操作系统就会把这个可执行文件加载到内存,形成进程,此时进程有一个虚拟的地址空间(内存空间) linux有个nm命令:能够列出可执行文件中的全局变量存放的地址; 测试代码如下: // 演示进程下内存分布 // #include <iostream> #include <time.h > #include <stdio.h> using namespace std; int *ptest

哲学天空的博客 232

SAP MM模块后续借记、后续贷记、贷方凭证简介

在SAP系统中,后续借记、后续贷记和贷方凭证是处理供应商发票、采购和付款过程中常见的财务交易。

我小时候很黑的博客 3270

《C++新经典对象模型》之第4章 数据语义学

4.1.2 成员函数参数类型的确定时机(最近碰到原则) 04.01.cpp 4.2 进程内存空间布局 最高内存地址 栈区(向下增长) 堆区(向上增长) 数据段(含BSS段) 代码段 最低内存地址进程虚拟地址空间(内存)划分: (1)栈(堆栈/栈区):局部变量等。 (2)堆(堆区):new、malloc等申请内存空间。 (3)BSS段:未初始化全局变量,初始化为0的全局变量。 (4)数据段:已初始化的全局变量,包含BSS段。 (5)代码段:存放程序执行代码。Linux上列出可执行文件中全局变量等存放位置的

yxqq378287007的博客 920

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C++实现内存地址空间布局(ASL):自定义堆栈、代码段与数据段的内存分配

大家好,今天我们来深入探讨C++中内存地址空间布局(Address Space Layout, ASL)的实现,以及如何自定义堆栈、代码段和数据段的内存分配。传统的操作系统负责管理进程的内存空间,但在某些特定场景下,例如嵌入式系统、裸机编程或者需要高度定制化的内存管理策略时,我们就需要自己来控制内存的分配和布局。理解内存地址空间布局:回顾典型的内存地址空间布局,包括代码段、数据段、堆、栈等。自定义内存区域:如何使用C++分配和管理自定义的内存区域。手动分配代码段:探讨将代码放置到特定内存地址的方法。

weixin_41455464的博客 695

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Linux程序内存空间布局以及实战

一典型内存空间布局 1代码段(.txtt segment):代码段通常是指存放程序执行代码的一块内存区域。 2初始化数据段(.data segment):通常是指用来存放程序已初始化的全局变量的一块内存区域。 3未初始化数据段(.bss segment):通常是用来存放程序未初始化的全局变量的一块内存区域。 4堆(heap):堆是用于存放进程运行中被动态分配内存段,它的大小并...

实践求真知 664

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

进程内存空间布局

// project100.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "pch.h" #include <iostream> #include <time.h > #include <stdio.h> using namespace std; int *ptest = new int(120); int...

昔拉的博客 237

C 程序的内存空间布局

C 程序的内存空间布局表格中, 从上到下为高地址到低地址方向 segment 含义 argument and environment 命令行参数和环境变量(环境表和环境字符串) stack 栈 heap 堆 bss 未初始化数据段 data 初始化数据段 text 正文段 1. 自由存储区: C++中, 堆是由 new 和 delete 管理的,

王慧勇 2275

C++对象模型之数据语义学

前言 本次笔记记录如下知识点 数据成员绑定时机 进程内存空间布局 数据成员布局 一、数据成员绑定时机 成员函数函数体的解析时机 如果成员变量和全局变量重复了,那么成员函数在内部调用时,会优先调用成员变量,因为编译器对函数体内部的变量进行解析时,是从整个类定义完成之后进行的。 如下示例 string myvar; class Base { public: int myfunc() { return myvar; } private: int myvar; }; int main()

qq_40223389的博客 253

【Linux进程概念——下】验证进程地址空间的基本排布 | 理解进程地址空间 | 进程地址空间如何映射至物理内存(页表的引出) | 为什么要存在进程地址空间 | Linux2.6内核进程调度队列

文章目录【写在前面】一、程序地址空间二、进程地址空间三、 【写在前面】 一、程序地址空间 这个概念比较重要,之前我们也涉及过 —— 我们在语言上定义的各种变量等在内存中的分布情况,如果没有听说过,那么你的 C/C++ 是不可能学好的。 其实对于这块,我们一直是有误区的。 二、进程地址空间 三、 ...

DanceBit的博客 1652

Linux学习之内存空间布局

Linux进程内存管理的对象都是虚拟内存,每个进程先天都有0-4G的各自互不干涉的虚拟内存空间,0-3G是用户空间执行用户自己的代码,高1GB的空间是内核空间执行Linux系统调用,这里存放着整个内核的代码和所有的内核模块,用户所看到和接触的都是该虚拟地址,并不是实际的物理内存地址。Linux下一个进程在内存里有三部分的数据,就是“代码段”、“堆栈段”和“数据段”。代码段就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。堆栈段存放的就是子程序的返回地址、子程序

m0_65292176的博客 1287
上一篇: C++对象模型(1)-- 对象模型概述
下一篇: C++对象模型(3)-- 类对象所占用的空间
老蔡编程
博客等级 码龄23年 48粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值