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

【QandA C++】内存泄漏、进程地址空间、堆和栈、内存对齐、大小端和判断、虚拟内存等重点知识汇总

目录

内存泄漏

内存模型 、进程地址空间

堆和栈的区别

内存对齐

大端小端及判断

虚拟内存有什么作用


内存泄漏

概念:

是指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况, 内存泄漏并不是指内存在物理上的消失, 而是应用程序分配了某段内存后, 因为设计错误, 失去了对该段内存的控制, 因而造成了内存的浪费.

  1. new和malloc申请资源使用后, 没有用delete和free释放
  2. 子类继承父类时, 父类的析构函数不是虚函数
  3. 未关闭的文件或资源

危害:

长期运行的程序出现内存泄漏, 影响很大; 出现内存泄漏会导致响应越来越慢, 最终卡死.

避免:

  • 计数法:使用new或者malloc时,让该数+1,delete或free时,该数-1,程序执行完打印这个计数,如果不为0则表示存在内存泄露
  • 一定要将基类的析构函数声明为虚函数
  • 对象数组的释放一定要用delete []
  • 有new就有delete,有malloc就有free,保证它们一定成对出现
  • 出问题了使用内存泄漏工具检测。

内存泄漏非常常见,解决方案分为两种:

  1. 事前预防型。如智能指针等。
  2. 事后查错型。如泄漏检测工具。
  • Linux下可以使用Valgrind工具
  • Windows下可以使用CRT库

内存模型 、进程地址空间


如上图,从低地址到高地址,用户空间内存,从低到高分别是 6 种不同的内存段:

  • 代码段,包括二进制可执行代码。只读,包含一些只读的变量
  • 数据段,包括已初始化的静态常量和全局变量;
  • BSS 段,包括未初始化的静态变量和全局变量;
  • 堆段,包括动态分配的内存,从低地址开始向高地址增长;动态申请内存用,由new分配的内存块,其释放由程序员控制(一个new对应一个delete)
  • 文件映射段,包括动态库、共享内存等,从低地址开始向上增长;最后还有一个共享区,位于堆和栈之间。
  • 栈段,存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。在不需要时自动清除的存储区。

Linux下的进程地址空间具体是由mm_struct实现的

struct mm_struct{unsigned int code_start;unsigned int code_end;unsigned int init_start;unsigned int init_end;unsigned int uninit_start;unsigned int uninit_end;unsigned int heap_start;unsigned int heap_end;unsigned int stack_start;unsigned int stack_end;
};

比如堆向上增长,栈向下增长,实际上就是改变mm_struct中的堆和栈的起始指针来实现的!

为什么要有进程地址空间?

为了实现多任务操作系统中的多进程隔离和独立运行,以确保不同进程之间的互不干扰和安全性。

  1. 隔离和保护:每个进程都有自己独立的地址空间,使得不同进程之间的内存互不干扰。这种隔离性确保了一个进程的错误或恶意行为不会对其他进程造成影响,提高了系统的稳定性和安全性。
  2. 相对地址一致性:每个进程都认为自己的地址空间是从0开始的,并且认为看到的是相同的地址空间范围。这种相对地址一致性使得进程可以使用相对地址进行内存操作,而不必关心其他进程的地址空间。
  3. 独立内存:每个进程都认为自己独占内存,可以自由分配和管理自己的内存资源。这使得进程可以在不互相干扰的情况下运行,并且不需要担心其他进程的内存使用情况。
  4. 虚拟内存:进程地址空间还支持虚拟内存的概念,允许操作系统在物理内存有限的情况下为每个进程提供大于物理内存的虚拟内存空间。这通过将部分数据存储在磁盘上,根据需要进行页面调度,提高了内存利用率。

堆和栈的区别

分配方式:

栈由编译器自动分配和管理,程序员无需手动控制栈内存的分配和释放。局部变量、函数参数以及函数调用上下文等都存储在栈上。

堆由程序员手动申请和释放,通常使用new(C++)或malloc(C)等函数分配内存,并使用delete(C++)或free(C)来释放内存。堆用于存储动态分配的数据,如动态数组、对象实例等。

空间大小限制:

栈的大小通常是有限的,具体大小由编译器或操作系统设置。栈的大小在编译时或运行时可以进行配置,但总是有限的。

堆的大小受限于系统可用的虚拟内存大小,通常比栈要大得多。堆大小受限于计算机系统中有效的虚拟内存(32bit 系统理论上是4G),所以堆的空间比较灵活,比较大

栈空间和堆区的大小是由操作系统和编译器决定的,不同系统和编译器可能会有不同的默认值。一般来说,栈空间默认是1MB或2MB,而堆区一般是1GB到4GB之间。

内存管理机制:

栈的内存管理由编译器自动完成,变量的生命周期与其作用域相对应。栈内存的分配和释放是隐式的,不需要程序员干预。

堆的内存管理由程序员手动控制。程序员负责显式地分配堆内存,并在不再需要时释放它。如果不正确地管理堆内存,可能会导致内存泄漏或悬挂指针等问题。

碎片问题:

栈内存通常不会出现碎片问题,因为栈的内存分配和释放都是线性的,按照函数调用的顺序进行。

堆内存可能会出现碎片问题,特别是在频繁进行动态内存分配和释放操作时。这可能导致内存空间的不连续,影响程序的性能。

生长方向:

栈的生长方向通常是向下的,即从高地址向低地址增长。这意味着栈的顶部在分配时逐渐向较低的地址移动。

堆的生长方向通常是向上的,即从低地址向高地址增长。堆内存在动态分配时逐渐向较高的地址分配。

分配效率:

栈由编译器和操作系统提供的支持,分配和释放内存的效率较高,通常采用硬件级别的指令进行操作。

堆的内存分配和释放需要程序员显式地调用函数,效率相对较低,并可能涉及复杂的内存管理机制。

形象的比喻

栈就像我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。

堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

内存对齐

内存对齐涉及到如何存储和访问数据以提高计算机的性能和效率。确保数据按照一定的规则存储在内存中,以便于有效地访问

结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。(即结构体的首地址处,即对齐到0处)
  2. 其他成员变量要对齐到最小对齐数的整数倍的地址处。
  3. 结构体的总大小为最大对齐数的整数倍

对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值。

注:VS中的默认对齐数为8,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数。

要修改编译器的默认对齐数,我们需要借助于以下预处理命令:#pragma pack(...)

为什么存在内存对齐?

平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些平台只能在某些地址处取得某些特定类型的数据,否则抛出硬件异常。

  • 比如,当一个平台要取一个整型数据时只能在地址为4的倍数的位置取得,那么这时就需要内存对齐,否则无法访问到该整型数据。

性能原因: 数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐内存,处理器需要作两次内存访问;而对齐的内存访问仅需一次。

其实结构体的内存对齐是拿空间来换取时间的做法

大端小端及判断

大端模式:是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中;地址由小向大增加,而数据从高位往低位放。

小端模式:是指数据的高位(就是权值较大的前面那几位)保存在内存的高地址中,而数据的低位,保存在内存的低地址中;地址由大向小增加,而数据从低位往高位放 。

大小端的意义在于确保数据在不同的计算机体系结构之间正确传递、解释和处理,保证系统之间的互操作性和数据的可移植性。

例如:32bit的数字0x12345678

所以在Socket编程中,往往需要将操作系统所用的小端存储的IP地址转换为大端存储,这样才能进行网络传输

端模式中的存储方式为:

端模式中的存储方式为:

如何在代码中进行判断呢?

方式一:使用强制类型转换-这种法子不错

#include <iostream>
using namespace std;
int main()
{int a = 0x1234;//由于int和char的长度不同,借助int型转换成char型,只会留下低地址的部分char c = (char)(a);if (c == 0x12)cout << "big endian" << endl;else if(c == 0x34)cout << "little endian" << endl;
}

方式二:巧用union联合体

#include <iostream>
using namespace std;
// union联合体的重叠式存储,endian联合体占用内存的空间为每个成员字节长度的最大值
union endian
{int a;char ch;
};
int main()
{endian value;value.a = 0x1234;//a和ch共用4字节的内存空间if (value.ch == 0x12)cout << "big endian"<<endl;else if (value.ch == 0x34)cout << "little endian"<<endl;
}

虚拟内存有什么作用

  • 虚拟内存可以使得进程对运行内存超过物理内存大小
  • 因为程序运行符合局部性原理,CPU 访问内存会有很明显的重复访问的倾向性,对于那些没有被经常使用到的内存,我们可以把它换出到物理内存之外,比如硬盘上的 swap 区域。当进程需要访问被置换出去的页时,它们会被重新加载到物理内存中。这种机制允许了更大的程序运行,而不受物理内存的限制。
  • 提高内存利用率:
  • 虚拟内存系统可以更好地利用物理内存资源。只有进程当前需要的部分内存被加载到物理内存中,而不是将整个程序加载到内存中。这减少了内存浪费,允许多个进程在有限的物理内存中共存。
  • 虚拟内存为每个进程提供了独立的地址空间
  • 每个进程有自己的页表,这样,一个进程无法直接访问其他进程的内存,从而提高了安全性和隔离性。即使两个进程使用相同的虚拟地址,它们映射到不同的物理内存位置。
  • 页表里的页表项中除了物理地址之外,还有一些标记属性的比特,比如控制一个页的读写权限,标记该页是否存在等。在内存访问方面,操作系统提供了更好的安全性。

相关文章:

【QandA C++】内存泄漏、进程地址空间、堆和栈、内存对齐、大小端和判断、虚拟内存等重点知识汇总

目录 内存泄漏 内存模型 、进程地址空间 堆和栈的区别 内存对齐 大端小端及判断 虚拟内存有什么作用 内存泄漏 概念: 是指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况, 内存泄漏并不是指内存在物理上的消失, 而是应用程序分配了某段内存后, 因为设计错误…...

怒刷LeetCode的第12天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;贪心 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;双指针 方法二&#xff1a;KMP算法 方法三&#xff1a;indexOf方法 方法四&#xff1a;Boyer-Moore算法 方法五&#xff1a;Rabin-Karp算法…...

RabbitMQ实现秒杀场景示例

本文章通过MQ队列来实现秒杀场景 整体的设计如下图&#xff0c;整个流程中对于发送发MQ失败和发送到死信队列的数据未做后续处理 1、首先先创建MQ的配置文件 Configuration public class RabbitConfig {public static final String DEAD_LETTER_EXCHANGE "deadLetterE…...

如何提升网站排名优化(百度SEO优化,轻松提升排名)

在当今互联网时代&#xff0c;拥有一个优秀的网站是很重要的。而一个网站如果能够在搜索引擎上的排名很靠前&#xff0c;那么将会带来更多的流量、更多的用户和更多的利润。那么如何提升网站排名优化呢&#xff1f;蘑菇号www.mooogu.cn 百度SEO优化的5个规则 1.关键词选取要合…...

CountDownLatch 和 CyclicBarrier 用法以及区别

在使用多线程执行任务时&#xff0c;通常需要在主线程进行阻塞等待&#xff0c;直到所有线程执行完毕&#xff0c;主线程才能继续向下执行&#xff0c;主要有以下几种可选方式 1. 调用 main 线程的 sleep 方法 一般用于预估线程的执行时间&#xff0c;在主线程内执行线程sleep…...

9.9喝遍“茶、奶、果、酒”,茶饮价格战是因为“无活可整”?

“家人们谁懂啊&#xff0c;周一瑞幸周二奈雪周三茶百道周四库迪周五古茗周六coco&#xff0c;9块9根本喝不完&#xff01;” 紧随咖啡的9.9大战&#xff0c;茶饮们也在今年加速“蜜雪冰城化”&#xff0c;9.9变成了一种潮流。伴随着茶百道、coco、奈雪的茶等品牌把9.9玩出了更…...

echarts 学习网址

1、PPChart 网址&#xff1a;PPChart - 让图表更简单 2、YX-Chartlib 网址&#xff1a;http://chartlib.datains.cn3、isqqw 网址&#xff1a;echarts图表集4、makeapie 网址&#xff1a;makeapie echarts社区图表可视化案例5、Chart.Top 网址&#xff1a;chart.top - 让图…...

android源码编译

整包编译 导入环境变量 source ./build/envsetup.shlunch&#xff1a;选择平台编译选项make&#xff1a;执行编译 编译单个apk 进入到apk mk所在路径 mma...

盘点双电机驱动技术

对于电动汽车来说&#xff0c;双电机相对于单电机加主减速器或变速箱的方案在提高驱动效率方面的优势&#xff1a; 第一&#xff0c;单电机在低速、高速轻载等情况下&#xff0c;效率降低比较严重。 电动机的高效区间虽然比内燃机大得多&#xff0c;但是汽车的转速和转矩要求…...

ubuntu下用pycharm专业版连接AI服务器及其docker环境

一&#xff1a;用pycharm专业版连接AI服务器 1、首先在自己电脑上新建一个文件夹&#xff0c;后续用于映射服务器上自己所要用的项目文件 2、用pycharm专业版打开该文件夹&#xff0c;作为一个项目打开 3、然后在工具->部署->配置 4、配置中形式如下&#xff1a; 点击左…...

IntentFilter笔记

一、action <intent-filter>中可以有多个action&#xff0c;Intent只要匹配其中1个action即匹配成功<intent-filter>没有action&#xff0c;任何Intent无法与之匹配<intent-filter>中有action&#xff0c;Intent中没有action时可以与之匹配成功<intent-fi…...

【二叉树】——链式结构(快速掌握递归与刷题技巧)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…...

项目管理—项目普遍存在的问题

软件公司有开发业务&#xff0c;在完成一个软件产品或实施项目时&#xff0c;常常会出现以下的状况&#xff1a; 开发人员不懂客户业务&#xff0c;一个高大上的规划&#xff0c;落地后的软件&#xff0c;只是机械的满足了基本功能&#xff0c;毫无易用性和科学性可言。 项目只…...

Ubuntu Seata开机自启动服务

1、创建service文件 在/lib/systemd/system目录下创建seata.service文件 [Unit] Descriptionalibaba seata Afternetwork.target Documentationhttps://seata.io/zh-cn/[Service] Userroot Grouproot Typeforking Environment"JAVA_HOME/usr/local/programs/jdk-8u333-li…...

腾讯mini项目-【指标监控服务重构】2023-08-26

今日已办 Venus 的 Trace 无感化 定义 handler 函数 fiber.Handler 的主要处理逻辑返回处理中出现的 error返回处理中响应 json 的函数 // handler // Description: // Author xzx 2023-08-26 18:00:03 // Param c // Return error // Return func() error : function for …...

《Essential C++》之(面向过程泛型编程)

目录 &#x1f33c;面向过程的编程风格 -- 第2章 &#x1f348;2.2 &#x1f348;2.4 &#x1f348;2.5 &#x1f348;2.6 &#x1f33c;泛型编程风格 -- 第3章 &#x1f34d;3.1 &#x1f34d;3.4 前言 要求 完整代码 输入输出 &#x1f33c;面向过程的编程风…...

机器学习笔记:adaBoost

1 介绍 AdaBoost&#xff08;Adaptive Boosting&#xff09;是一种集成学习方法&#xff0c;它的目标是将多个弱分类器组合成一个强分类器 通过反复修改训练数据的权重&#xff0c;使得之前分类错误的样本在后续的分类器中得到更多的关注每一轮中&#xff0c;都会增加一个新的…...

Anchor DETR

Anchor DETR(AAAI 2022) 改进&#xff1a; 提出了基于anchor的对象查询提出Attention变体-RCDA 在以前DETR中&#xff0c;目标的查询是一组可学习的embedding。然而&#xff0c;每个可学习的embedding都没有明确的意义 &#xff08;因为是随机初始化的&#xff09;&#xff…...

适合在家做的副业 整理5个,有电脑就行

今天&#xff0c;我们不说别的&#xff0c;整理5个适合个人在家单干的副业。需要电脑&#xff0c;如果你没电脑就不用看了&#xff0c;最后两个&#xff0c;我们也在做&#xff0c;你可以看到最后了解。这些副业&#xff0c;大家多去实践操作&#xff0c;前期&#xff0c;每月三…...

Android WebSocket

WS Android WebSocket 资源 名字资源AAR下载GitHub查看Gitee查看 Maven 1.build.grade allprojects {repositories {...maven { url https://jitpack.io }} }2./app/build.grade dependencies {implementation com.github.RelinRan:WS:2022.2023.9.23.1 }初始化 配置权…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...

深度解析:etcd 在 Milvus 向量数据库中的关键作用

目录 &#x1f680; 深度解析&#xff1a;etcd 在 Milvus 向量数据库中的关键作用 &#x1f4a1; 什么是 etcd&#xff1f; &#x1f9e0; Milvus 架构简介 &#x1f4e6; etcd 在 Milvus 中的核心作用 &#x1f527; 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...

【Java多线程从青铜到王者】单例设计模式(八)

wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本&#xff0c;sleep也是可以指定时间的&#xff0c;也就是说时间一到就会解除阻塞&#xff0c;继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒)&#xff0c;wait能被notify提前唤醒&#xf…...