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

news2024/12/24 3:04:26

在前面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段的下面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1072383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

婚庆行业通过微信小程序开发可以实现什么功能

婚庆微信小程序是一种针对结婚人群提供一站式婚礼服务的移动应用&#xff0c;包括婚礼策划、酒店预订、婚车租赁、婚纱摄影、婚礼用品等多个方面。随着互联网技术的发展和移动设备的普及&#xff0c;婚庆微信小程序已经成为越来越多新人选择婚礼服务的重要渠道。那么&#xff0…

动态规划-杨辉三角(leetcode)

1. 题目 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1 输出: [[1]] …

airflow的使用

安装&#xff1a; pip install airflow 初始化数据库 airflow db init 添加用户 airflow users create \ --username admin \ --firstname admin \ --lastname admin \ --role Admin \ --email adminadmin.com 运行airflow&#xff0c;只需要这一个命令即可。 airflow sta…

修炼k8s+flink+hdfs+dlink(三:安装dlink)

一&#xff1a;mysql初始化。 mysql -uroot -p123456 create database dinky; grant all privileges on dinky.* to dinky% identified by dinky with grant option; flush privileges;二&#xff1a;上传dinky。 上传至目录/opt/app/dlink tar -zxvf dlink-release-0.7.4.t…

美团面试:Redis怎么做高可用、高并发架构?

说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 如果使用 Redis 的场景很简单&#xff0c;只使用单机版 Redis 会…

探索未来绘画:AI 的视觉创造力 | 开源专题 No.30

这一系列开源项目代表了开源社区在图像处理和创造性媒体生成方面的突出成就。它们的共同特点在于&#xff0c;它们都致力于提供出色的用户体验&#xff0c;让用户能够轻松实现复杂的图像处理和生成任务。这些项目坚守着开放源代码的理念&#xff0c;通过活跃的社区支持和高度灵…

docker compose的安装和使用

docker-copose 介绍 docker-compose 是一个容器编排工具&#xff08;自动化部署、管理&#xff09;; 它用来在单台 Linux 服务器上运行多个 Docker 容器; docker-compose 使用YAML文件来配置所有需要运行的 Docker 容器&#xff0c;该 YAML 文件的默认名称为 docker-compose.…

阿里云服务器ECS是什么?云服务器详细介绍

阿里云服务器ECS英文全程Elastic Compute Service&#xff0c;云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;阿里云提供多种云服务器ECS实例规格&#xff0c;如经济型e实例、通用算力型u1、ECS计算型c7、通用型g7、GPU实例等&#xff0c;阿里云服务器网分享阿…

2023/10/8总结

安装Sass pnpm i sass -D 电商 网站 的首页 通常会比较长 用户 不一定能访问到 页面靠下面的图片 &#xff0c;这类图片可以通过 懒加载 优化手段可以做到 只有 进入视口区域才发送图片请求 指令写法&#xff1a; <img v-img-lazy"item.picture"/> 路由缓存…

推荐几个技术学习的网站

USB中文网 点击打开 USB中文网 - USB技术开发交流USB中文网是国内领先的专业USB技术网站&#xff0c;提供USB开发入门教程&#xff0c;USB设备开发&#xff0c;USB驱动开发&#xff0c;USB摄像头&#xff0c;USB麦克风&#xff0c;USB存储设备&#xff0c;USB-HID设备&#x…

AI驱动的3D模型无缝纹理生成

创建无缝纹理一直是一个需要艺术技巧的劳动密集型过程。 然而&#xff0c;随着稳定扩散模型&#xff08;Stable Diffusion&#xff09;的出现&#xff0c;情况发生了变化。 通过将文本转换为逼真、无边界的图像&#xff0c;稳定扩散彻底改变了纹理创建&#xff0c;使其变得易于…

计算机体系结构中的8个伟大思想

一、面向摩尔定律的设计 计算机设计者面临的一个永恒的问题就是摩尔定律。摩尔定律指出&#xff1a;集成电路上可容纳的晶体管数每18~24个月就会翻一番。由于计算机设计通常需要几年时间&#xff0c;因此项目结束时芯片的集成度较之项目开始时&#xff0c;很容易翻一番甚至翻两…

数据结构与算法设计分析——分治法

目录 一、分治法的定义二、分治法的基本步骤三、分治法的应用&#xff08;一&#xff09;查找算法二分&#xff08;折半&#xff09;查找 &#xff08;二&#xff09;排序算法1、交换排序——快速排序2、归并排序 一、分治法的定义 分而治之可称为分治法&#xff0c;即逐个击破…

Qt开发学习笔记02

将窗口设为提示框 Qt::ToolTipQt 数据库连接池 #ifndef SQLITE_H #define SQLITE_H#include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery> #include <QQueue> #include <QMutex> #include <QDebug> #include "../con…

安装spark并配置高可用

0、说明 上一篇文章讲了如何安装hadoop&#xff0c;这里将spark的详细安装步骤记录在这里。 其中实现了spark的高可用配置&#xff0c;即将zookeeper配置到spark集群中。对于资源管理也配置了yarn模。并开启了spark-sql的配置&#xff0c;可以通过jdbc链接spark。 spark 集群…

Three.js真实相机畸变效果模拟

有没有想过如何在 3D Web 应用程序中模拟物理相机&#xff1f; 在这篇博文中&#xff0c;我将向你展示如何使用 Three.js和 OpenCV 来完成此操作。 我们将从模拟针孔相机模型开始&#xff0c;然后添加真实的镜头畸变。 具体来说&#xff0c;我们将仔细研究 OpenCV 的两个失真模…

【C++】Stack Queue -- 详解

一、stack的介绍和使用 1、stack的介绍 https://cplusplus.com/reference/stack/stack/?kwstack 1. stack 是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack 是作为容器适配器被…

改变世界-生成式人工智能

麦肯锡在其《生成人工智能的经济潜力&#xff1a;下一个生产力前沿》中声称&#xff0c;“ChatGPT、GitHub Copilot、Stable Diffusion 等生成式人工智能应用程序以 AlphaGo 没有的方式吸引了世界各地人们的想象力&#xff0c;这要归功于它们广泛的实用性——几乎任何人都可以使…

[mysql工具]Windows批处理方式实现MySQL定期自动备份

Windows批处理方式实现MySQL定期自动备份 对MySQL数据库而言&#xff0c;大部分数据库工具都具有备份功能&#xff0c;但并不能做到定期自动备份&#xff0c;在Windows环境下&#xff0c;手工备份MySQL是很繁琐的&#xff0c;所以我们通过MySQL提供的备份命令mysqldump&#xf…

如何防止重复提交订单

产生的原因 一种是由于用户在短时间内多次点击下单按钮&#xff0c;或浏览器刷新按钮导致。另一种则是由于Nginx或类似于SpringCloud Gateway的网关层&#xff0c;进行超时重试造成的。由于网速等原因造成页面卡顿&#xff0c;用户重复刷新提交页面黑客或恶意用户使用 postman…