【C++】C\C++内存管理

下面是围绕C\C++内存管理这一块知识谈论相关的内存管理机制,有需要借鉴即可。

同时,我在下面也放了快速建立链表的模板,方便oj题目拿到vs上进行调试。

内存管理目录

  • 1.CPP内存管理
    • 1.1new、delete关键字概念
    • 1.2特性
    • 1.3总结
  • 2.new、delete的底层
    • 2.1new的底层是operator new:
    • 2.2delete的底层是operator delete
    • 2.3总结
  • 3.内存泄漏
    • 3.1概念
  • 4.快速生成链表模板

在介绍本节博客之前,请思考为什么要进行内存划分?或者说内存为什么要划分为不同的区域?直接一整块使用多好。

答案是为了方便内存管理。这就类似于我们为什么要对全国进行划分不同给的省份?正是因为划分了不同的省份可以方便管理才这样做的。
在这里插入图片描述

1.CPP内存管理

针对于C/CPP语言,我们一般将内存划分为如下几个不同的区域:
在这里插入图片描述
注:语言层面名称:静态区、常量区
操作系统层面名称:数据段、代码段

请回答下面代码中的变量分别存储在计算机内存的哪个区域?

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
 static int staticVar = 1;
 int localVar = 1;
 int num1[10] = { 1, 2, 3, 4 };
 char char2[] = "abcd";
 const char* pChar3 = "abcd";
 int* ptr1 = (int*)malloc(sizeof(int) * 4);
 int* ptr2 = (int*)calloc(4, sizeof(int));
 int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
 free(ptr1);
 free(ptr3);
}

在这里插入图片描述
下面是答案:

在这里插入图片描述

对于上面所介绍的这些内存空间,我们作为编写代码的人应该重点关注哪一块区域呢?
答:
是堆空间,因为堆是系统把一部分操作权限给到我们编写代码的人的,包括一些堆的空间申请,堆的空间释放…

在C语言中,我们常用malloc\realloc\calloc进行对堆空间的申请和free释放
因而想要使用堆空间,下面代码基本说是"必经之路"。

思考:malloc、realloc、calloc的区别?
答:
malloc:申请一块空间
realloc:更改空间大小,支持原地扩容和异地扩容
calloc:申请一块空间并初始化

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}

我们申请一块空间是需要先把地址放到一个指针变量里,然后再进行检查…程序复杂且重复。
CPP为了解决这个问题,通过对malloc函数进行封装加工处理,形成了new关键字,通过对free函数的封装加工处理,形成了delete关键字。

1.1new、delete关键字概念

CPP提供的new与delete相对于C语言中的malloc与free的提升主要集中在两个方面,一是用法更加简单,二是功能更加强大

1.2特性

  • 1.用法上,更加简单

    • new关键字替代了malloc(sizeof())和检查那一大堆
      在这里插入图片描述
  • 2.功能上,更加强大

    • ①开始:可以支持在开辟空间时候初始化
      在这里插入图片描述

    • ②创建过程:可以支持自定义类型的空间开辟,new自动调用构造函数,delete自动调用对应的析构函数(重点)
      在这里插入图片描述

    • ③结束:new失败了会抛异常,不用指针检查是否为空

1.3总结

在这里插入图片描述

从上面看来,new和delete的语法引入大大方便了我们对堆空间的使用。那其底层是如何实现的呢?

2.new、delete的底层

2.1new的底层是operator new:

new —>operator new + n次构造函数(自定义类型) —>malloc
new[] —> operator new[] —> operator new + n次构造函数(自定义类型) —> malloc

我们以下面代码为例,看其汇编解析其底层:
在这里插入图片描述
在这里插入图片描述

思考:为什么要定义operator new对malloc实现封装?
答:
①要实现new失败要抛异常
②要调用自定义类型的构造函数

思考:直接new空间,编译器是怎么确定要开多大空间的?C语言中我们需要给空间大小的。
答:通过sizeof编译时进行计算,sizeof是一种运算符,其在编译期间确定,而不是在运行时。

思考:为什么上面自定义类型开空间多开8个字节的空间?
答:主要是多开几个字节的空间来存储这块空间多大,方便下一步delete释放时候要释放多少空间。
在这里插入图片描述

注:下图蓝色区域是新开空间存储相关内容的空间区域,红色则是存储这块空间是多大的,方便delete的删除操作。
在这里插入图片描述

2.2delete的底层是operator delete

delete —> 析构函数 + operator delete —> free
注意:有些delete[]会进一步调用operator delete

思考:operatr delete是先调用析构函数还是先调用free?
答:先调用析构函数
在这里插入图片描述

创建与销毁一定要对等使用,即:

  • 开辟空间:new[] ,释放空间:delete[]
  • 开辟空间:new,释放空间:delete

思考:为什么?
在这里插入图片描述

2.3总结

在这里插入图片描述

3.内存泄漏

3.1概念

是指一块内存空间申请了不用却也不还给系统。

共分为两种情况:

  • 1.堆内存泄露
    堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
  • 2.系统资源泄露
    指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

4.快速生成链表模板

#include<iostream>
using namespace std;

struct ListNode
{
	int _val;
	ListNode* _next;

	//构造函数初始化
	ListNode(int val = 0)
		:_val(val)
		, _next(nullptr)
	{}
};

ListNode* CreatList(int n)
{
	ListNode head(-1);//生成一个类对象
	ListNode* tail = &head;//尾指针

	int val;
	printf("请依次输入%d个节点的val值:>\n", n);

	for (int i = 0; i < n; i++)
	{
		//cin >> val;
		val = i;
		tail->_next = new ListNode(val);
		tail = tail->_next;
	}

	return head._next;
}

void test2()
{
	ListNode* head = CreatList(100);
	ListNode* pcur = head;
	for (int i = 0; i < 100; i++)
	{
		cout << pcur->_val << "  ";
		pcur = pcur->_next;
	}
}

EOF

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】贪吃蛇详解(附源码)

一、贪吃蛇实现效果 【C语言】贪吃蛇&#xff08;控制台&#xff09; 二、源码 &#x1f388;&#x1f388;&#x1f388;Snake 残风也想永存/C语言项目 - 码云 - 开源中国 (gitee.com)&#x1f388;&#x1f388;&#x1f388; 三、如何使用C语言去实现一个贪吃蛇&#xff1f…

每日一题:地下城游戏

恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0…

ThreeJs 环境配置及遇到问题的解决方法

一、环境搭建 ThreeJs在实际在实际使用中更多的是结合框架开发例如&#xff1a;vue框架、react框架&#xff0c;在使用时需要配置开发环境&#xff0c;本文使用的是vscode ThreeJs NodeJs vue 1、ThreeJs安装 下载路径&#xff1a;GitHub - mrdoob/three.js: JavaScript…

CentOS命令大全:掌握关键命令及其精妙用法!

CentOS是一种流行的开源企业级Linux发行版&#xff0c;它基于Red Hat Enterprise Linux (RHEL)的源代码构建。对于系统管理员和运维工程师来说&#xff0c;掌握CentOS的常用命令至关重要。 这些命令不仅可以帮助管理服务器&#xff0c;还可以进行故障排查、性能监控和安全加固等…

【idea】idea 中 git 分支多个提交合并一个提交到新的分支

一、方法原理讲解 我们在 dev 分支对不同的代码文件做了多次提交。现在我们想要把这些提交都合并到 test 分支。首先我们要明白四个 git 操作&#xff0c; commit&#xff1a;命令用于将你的代码变更保存到本地代码仓库中&#xff0c;它创建了一个新的提交&#xff08;commit…

Ubuntu编译安装MariaDB并进行初始化配置

Ubuntu编译安装MariaDB并进行初始化配置 1. 编译安装MariaDB2. 配置MariaDB3. Docker安装MariaDB 1. 编译安装MariaDB MariaDB官方安装文档&#xff1a;https://mariadb.com/kb/en/Build_Environment_Setup_for_Linux/    下载MariaDB源码&#xff1a;https://mariadb.org/ma…

Spring Boot 如何实现缓存预热

Spring Boot 实现缓存预热 1、使用启动监听事件实现缓存预热。2、使用 PostConstruct 注解实现缓存预热。3、使用 CommandLineRunner 或 ApplicationRunner 实现缓存预热。4、通过实现 InitializingBean 接口&#xff0c;并重写 afterPropertiesSet 方法实现缓存预热。 1、使用…

TCP-模拟BS架构通信

简介 bs是通过浏览器进行访问的每次访问都会开启一个短期的socket用来访问服务器的资源 响应报文的格式 服务端 bs架构中的b是浏览器&#xff0c;不需要我们书写&#xff0c;我们只需要书写服务端即可 服务端 public class Server {public static void main(String[] args) {S…

[C++]22:C++11_part_one

C11 一.列表初始化&#xff1a;1.{}初始化&#xff1a;2.C11扩大了列表初始化的范围&#xff1a;3.std::initializer_list1.简单类型的列表初始化&#xff1a;2.复杂类型的列表初始化3.实现vector的列表初始化4.实现list的列表初始化&#xff1a;5.不支持列表初始化&#xff1a…

制作一个RISC-V的操作系统十六-系统调用

文章目录 用户态和内核态mstatus设置模式切换核心流程封装代码背景解释代码示例解析解释目的 用户态和内核态 mstatus设置 此时UIE设置为1和MPIE为1&#xff0c;MPP设置为0 代表当前权限允许UIE中断发生&#xff0c;并且在第一个mret后将权限恢复为用户态&#xff0c;同时MIE也…

易错知识点(学习过程中不断记录)

快捷键专区&#xff1a; 注释&#xff1a;ctrl/ ctrlshift/ 保存&#xff1a;ctrls 调试&#xff1a; 知识点专区&#xff1a; 1基本数据类型 基本数据类型有四类&#xff1a;整型、浮点型、字符型、布尔型&#xff08;Boolean&#xff09;&#xff0c; 分为八种&#xff…

UE5 GAS开发P40 周期性效果,持续治疗

Periodic Gameplay Effects周期性的游戏效果 它们在一段时间内以固定的间隔重复应用到目标上。这种效果通常用于表示持续性伤害、治疗或其他影响&#xff0c;例如中毒、灼烧或回复效果。 修改GE_CrystalHeal,在Period改为每0.1秒执行一次 假如同时有三个持续时间在进行,那么这…

STM32与OLED显示屏通信(四针脚和七阵脚)

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. 单片机调试 2. OLED简介 3. 接线 4. OLED驱动函数 4.1 四针脚版本 OLED.c OLED.h OLED_Font.h 4.2 七针脚版本 引脚连接 OLED.c OLED.h OLED_Font.h 5. 主函数 工程文件模板 1. 单片机…

linux下安装deepspeed

安装步骤 一开始安装deepspeed不可以使用pip直接进行安装。 这时我们需要利用git进行clone下载到本地&#xff1a; git clone https://github.com/microsoft/DeepSpeed.git 进入到deepspeed的安装目录下 cd /home/bingxing2/ailab/group/ai4agr/wzf/Tools/DeepSpeed 激活…

verilog 从入门到看得懂---matlab 自动生成verilog

matlab 的强大不用多说&#xff0c;以前经常用simulink 生成c&#xff0c;最近尝试用simulink进行了verilog的生成&#xff0c;方法也很简单。 一个简单的示例如下。 1&#xff0c;新建一个模型文件&#xff0c;并且根据需要进行模型搭建 2.配置HDL生成模块 3.点击 generation…

纯血鸿蒙APP实战开发——全局状态保留能力弹窗

全局状态保留能力弹窗 介绍 全局状态保留能力弹窗一种很常见的能力&#xff0c;能够保持状态&#xff0c;且支持全局控制显隐状态以及自定义布局。使用效果参考评论组件 效果图预览 使用说明 使用案例参考短视频案例 首先程序入口页对全局弹窗初始化&#xff0c;使用Globa…

Linux学习之路 -- 进程篇 -- 自定义shell的编写

前面介绍了进程程序替换的相关知识&#xff0c;接下来&#xff0c;我将介绍如何基于前面的知识&#xff0c;编写一个简单的shell&#xff0c;另外本文的所展示的shell可能仅供参考。 目录 <1>获取用户的输入和打印命令行提示符 <2>切割字符串 <3>执行这个…

qt-C++笔记之滑动条QSlider和QProgressBar进度条

qt-C笔记之滑动条QSlider和QProgressBar进度条 —— 2024-04-28 杭州 本例来自《Qt6 C开发指南》 文章目录 qt-C笔记之滑动条QSlider和QProgressBar进度条1.运行2.阅读笔记3.文件结构4.samp4_06.pro5.main.cpp6.widget.h7.widget.cpp8.widget.ui 1.运行 2.阅读笔记 3.文件结构…

智慧供热一站式热网平衡多功能集成系统

供热管理地域分散的现实&#xff0c;决定必须采用先进技术手段开发软件系统&#xff0c;使各管理单位互联互通。在多年技术积累的基础上&#xff0c;公司采用目前成熟而且领先的技术架构&#xff0c;研发了适用于多个组织机构集中式管理的供热管理软件。使管理在技术上不再受地…

经典的目标检测算法有哪些?

一、经典的目标检测算法有哪些&#xff1f; 目标检测算法根据其处理流程可以分为两大类&#xff1a;One-Stage&#xff08;单阶段&#xff09;算法和Two-Stage&#xff08;两阶段&#xff09;算法。以下是一些经典的目标检测算法&#xff1a; 单阶段算法: YOLO (You Only Loo…