内存管理(C/C++)

news2024/11/19 16:45:54

内存管理(C/C++)

  • C/C++内存分布
  • C语言中的动态内存管理方式
  • C++中动态内存管理
    • new / delete 操作内置类型
    • new 和 delete 操作自定义类型
  • operator new 和 operator delete 函数
    • operator new 和 operator delete 函数
  • new 和 delete 的实现原理
    • 内置类型
    • 自定义类型
  • 定位 new 表达式(placement-new)
  • 常见面试题
    • malloc / free 和 new / delete 的区别
    • 内存泄漏
      • 什么是内存泄漏,内存泄漏的危害

C/C++内存分布

先介绍C/C++中程序内存区域的分划

在这里插入图片描述

观察下列代码,分析各数据在内存中所处的位置

int i = 1;
static int statici = 1;
void test()
{
	static int staticn = 1;
	int n = 1;
	
	int arr[10] = { 0 };
	char ch[] = "crush";
	const char* p = "crush";

	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);
}
A.栈   B.堆   C.数据段(静态区)   D.代码段(常量区)
i在哪里__                    statici在哪里__
staticn在哪里__              n在哪里__
arr[]在哪里__

ch[]在哪里__                 *ch在哪里__
p在哪里__                    *p在哪里__
ptr1在哪里__                 *ptr1在哪里__

sizeof(arr)=__
sizeof(ch)=__               strlen(ch)=__
sizeof(p)=__                strlen(p)=__
sizeof(ptr1)=__              

在这里插入图片描述

在这里插入图片描述

栈:存储非静态局部变量,函数参数,返回值等
堆:程序运行时进行内存分配
数据段:存储全局数据和静态数据
代码段:可执行程序,只读常量

C语言中的动态内存管理方式

malloc/calloc/realloc 和 free
代码如下

void test()
{
	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(ptr2)  这里需要free(ptr2)吗?
	free(ptr3);
}

由于已经在ptr2的基础上进行了扩容,所以不需要对ptr2进行释放,否则就会发生错误

在这里插入图片描述

C++中动态内存管理

new / delete 操作内置类型

void test()
{
	int* p1 = new int;                   //C++动态申请一个int类型的空间
	int* p2 = (int*)malloc(sizeof(int)); //C动态申请一个int类型的空间
	delete p1;
	free(p2);

	int* p3 = new int[10];                    //C++动态申请10个int类型的空间
	int* p4 = (int*)malloc(sizeof(int) * 10); //C动态申请10个int类型的空间
	delete p3;
	free(p4);

	int* p5 = new int(1);                //C++动态申请一个int类型的空间并初始化
	int* p6 = new int[5]{ 1,2,3,4,5 };   //C++动态申请5个int类型的空间并初始化
	delete p5;
	delete[] p6;
}

new/delete 和 malloc/free 针对内置类型没有任何区别

void test()
{
	//动态申请一个int类型的空间
	int* p1 = new int;
	//动态申请一个int类型的空间并进行初始化
	int* p2 = new int(1);
	//动态申请5个int类型的空间
	int* p3 = new int[5];
	delete p1;
	delete p2;
	delete[] p3;
}

在这里插入图片描述

C++动态申请和释放空间时,需要配对,若是单个元素,使用new/delete;若是多个元素使用new[]/delete[]

new 和 delete 操作自定义类型

class M
{
public:
	M()
		:_data(1)
	{
		cout << "M()" << endl;
	}
	~M()
	{
		cout << "~M()" << endl;
	}
private:
	int _data;
};

void test()
{
	//C++动态申请一个M类型的空间
	M* p1 = new M;
	//C动态申请一个M类型的空间
	M* p2 = (M*)malloc(sizeof(M));
	delete p1;
	free(p2);

	//C++动态申请5个M类型的空间
	M* p3 = new M[5];
	//C动态申请5个M类型的空间
	M* p4 = (M*)malloc(sizeof(M) * 5);
	delete[] p3;
	delete p4;
}

int main()
{
	M m;
	test();
	return 0;
}

在这里插入图片描述

在申请自定义类型的空间时,new会调用构造函数,delete也会调用析构函数;相反malloc 和 free 则不会

operator new 和 operator delete 函数

operator new 和 operator delete 函数

new / delete C++是进行动态内存申请和释放的操作符, operator newoperator delete是系统提供的全局函数,换一种说法便是,new 申请空间是通过调用 operator new来实现的,同理 delete 释放空间也是通过调用operator delete来实现的

本质上,operator new/operator delete的用法与 malloc/free 的功能完全一样,不同点在于,处理动态申请失败的方式不同;malloc申请失败返回NULL,operator new申请失败则会抛异常

以下三种动态申请空间和释放的效果是一样的

void test()
{
	int* p1 = new int;
	delete p1;

	int* p2 = (int*)operator new(sizeof(int));
	operator delete(p2);

	int* p3 = (int*)malloc(sizeof(int));
	free(p3);
}

在这里插入图片描述

new 和 delete 的实现原理

内置类型

申请的是内置类型的空间,new/delete 与 malloc/free 的区别在上面已经结束过,这里便不在赘叙

自定义类型

new的原理

  1. 调用operator new函数申请空间
  2. 在已经申请的空间上调用构造函数,完成对象的实例化

delete的原理

  1. 在已经申请的空间上调用析构函数,完成对象中资源的清理
  2. 调用operator delete函数释放对象的空间

new T[N]的原理

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
  2. 在已经申请的空间上调用N次构造函数

delete[]的原理

  1. 在释放的对象空间上调用N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

定位 new 表达式(placement-new)

定位new表达式是在已经分配的原始内存空间中调用构造函数初始化一个对象

使用格式
new(place-address)type或者
new(place-address)type(initalizer-list)

使用场景
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定位表达式进行显示调用构造函数并进行初始化

class M
{
public:
	M(int m = 0)
		:_m(1)
	{
		cout << "M()" << endl;
	}
	~M()
	{
		cout << "~M()" << endl;
	}
private:
	int _m;
};

void test()
{
	//p现在指向的是与M对象大小相同的一段空间
	//还未调用构造函数,所以指向的不算是对象
	M* p = (M*)operator new(sizeof(M));
	//定位new,显示调用构造函数并进行初始化已经申请的空间
	new(p)M;//new(p)M(1);
	//显示调用析构函数
	p->~M();
	operator delete(p);
}

常见面试题

malloc / free 和 new / delete 的区别

malloc/free 和 new/delete的共同点:都是从堆上申请空间,并且使用完之后需要进行释放

  1. malloc 和 free是函数,new和delete是操作符
  2. malloc申请的空间不进行初始化,new可以进行初始化
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需要在其后跟上空间的类型即可,如果多个对象,[]中指定对象个数即可
  4. malloc的返回值是void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
  6. 申请自定义类型对象时,malloc/free 只会开辟空间,不会调用构造函数和析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

内存泄漏

什么是内存泄漏,内存泄漏的危害

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

内存泄漏的危害:长期运行的程序出现泄漏,影响很大。

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

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

相关文章

【人工智能原理自学】激活函数:给机器注入灵魂

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;笔记来自B站UP主Ele实验室的《小白也能听懂的人工智能原理》。 &#x1f514;本文讲解激活函数&#xff1a;给机器注入灵魂&#xff0c;一起卷起来叭&#xff01; 目录一、“分…

已解决pandas正确创建DataFrame对象的四种方法(通过list列表、dict字典、ndarray、Series对象创建)

已解决&#xff08;pandas创建DataFrame对象失败&#xff09;ValueError: 4 columns passed, passed data had 2 columns 文章目录报错代码报错翻译报错原因解决方法创建DataFrame对象的四种方法1. list列表构建DataFrame2. dict字典构建DataFrame3. ndarray创建DataFrame4. Se…

【MySQL】十一,存储引擎

查看存储引擎 查看mysql提供什么存储引擎 设置系统默认的存储引擎 查看默认的存储引擎 show variables like %storage_engine%; SELECT default_storage_engine;修改默认的存储引擎 如果在创建表的语句中没有显式指定表的存储引擎的话&#xff0c;那就会默认使用 InnoDB 作…

08、ThingsBoard使用msa构建镜像并上传到Harbor

1、概述 今天讲解如何使用thingsboard源码中的msa模块来构建镜像,首先我先说一下这个模块的作用,很多人都不明白msa是如何构建镜像的,msa下面创建了很多模块,每个模块都是一个应用,就像我们平时微服务一样可以独自启动,thingsboard是使用这些模块去其它模块拉取代码过来…

卷积神经网络 Convolutional Neural Network (CNN)

CNNObservation 1Observation 2Benefit of Convolutional LayerMultiple Convolutional LayersComparision of Two StoriesObservation 3Convolutional Layers PoolingApplication: Playing GoTo learn more ...仅供个人学习&#xff0c;不具参考价值&#xff01; Image Class…

python代码运行速度有点慢 ? 教你使用多线程速度飞升

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 在我们爬取数据的时候,有时候它运行速度会非常慢 那么怎么解决呢? 这里给大家带来一个多线程的方法 我们用采集二手车来举例 环境使用: Python 3.8 Pycharm 模块使用: requests 数据请求模…

JVM类加载机制-让你明明白白的了解类的执行流程

一、类加载运行过程1.1 类加载到jvm的流程当我们使用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到jvm里。1.2 loadClass的类加载过程其中loadClass的类加载过程有如下几步&#xff1a;加载 >> 验证 >> 准备 >> 解析…

关于Visual Studio C++项目属性设置的说明

链接器—常规—输出文件 这里的输出文件指的是最终生成的exe文件 C/C–常规—附加包含目录 这里指的是需要include的一些头文件所在的 目录&#xff0c;可以提前在项目文件中建立好include文件&#xff0c;然后在这里设置&#xff0c;以后将一些自定义的include头文件放在这个…

Python之父强烈推荐,爬虫入门经典《python3网络爬虫开发实战》

实操性很强的一本工具书&#xff0c;由浅入深&#xff0c;深入浅出。前面从环境配置到爬虫原理、基本库和解析库的使用再到数据存储&#xff0c;一步步把基础打好&#xff0c;然后再分门别类介绍了Ajax、动态页、验证码、App的爬取、识别等&#xff0c;还讲解了代理使用、模拟登…

【Java】Spring中Aware接口的作用

Spring的几个aware接口的用法 ApplicationContextAware public interface ApplicationContextAware extends Aware {void setApplicationContext(ApplicationContext applicationContext) throws BeansException; }该接口仅有一个方法&#xff0c;用于设置Spring容器上下文。…

浅谈Springboot自动配置

目录 1.自动配置原理 2.自动配置案例 3.总结 1.自动配置原理 在一个Springboot程序中&#xff0c;我们只需要在main程序中使用springBootApplication注解即可标记为一个一个Springboot程序&#xff0c;然后使用 SpringApplication.run(TestMain.class,args) 代码即可创建…

多把锁,死锁,活锁,饥饿

目录 多把锁 多把锁的优缺点 活跃性 死锁 手写死锁 死锁的四个必要条件 定位死锁 jconsole运行命令 jps 定位进程 id&#xff0c;再用 jstack 定位死锁 死锁的三种场景 一个线程一把锁 两个线程两把锁 多个线程多把锁 解决死锁 活锁 饥饿 多把锁 现在有一个场…

Kali Linux ping扫描命令

1.命令介绍 kali的ping命令和centos linux的评命令许多参数都差不多&#xff0c;可以看一下我之前写的linuxping命令https://blog.csdn.net/qq_44652591/article/details/128439494 ping扫描是ping整个网络IP地址或单个IP&#xff0c;以查明它们是否活跃和响应的过程。ping也是…

用Kettle调用Restful API 接口

1 概述 kettle 中文名称叫水壶&#xff0c;是纯 java 开发&#xff0c;开源的 ETL工具&#xff0c;用于数据库间的数据迁移 。可以在 Linux、windows、unix 中运行。有图形界面&#xff0c;也有命令脚本还可以二次开发。当然它也可以用来调用Restful API 来采集数据&#xff0c…

【安全硬件】Chap.6 IC和半导体产业的全球化;芯片生产猜疑链与SoC设计流程;可能会存在的安全威胁: 硬件木马、IP盗版、逆向工程、侧信道攻击、伪造

【安全硬件】Chap.6 IC和半导体产业的全球化&#xff1b;芯片生产猜疑链与SoC设计流程&#xff1b;可能会存在的安全威胁: 硬件木马、IP盗版、逆向工程、侧信道攻击、伪造背景1. IC和半导体产业的全球化2. 芯片生产猜疑链——Untrusted IC Supply Chain Threats可能会存在的安全…

我只是把握好了这3点,1个月后成功拿下大厂offer!

目录 一、写在前面二、技术广度的快速准备三、技术深度的快速准备四、基础功底的快速准备五、下篇预告 一、写在前面 春节过后&#xff0c;即将迎来的是一年一度的金三银四跳槽季。 假如你准备在金三银四跳槽的话&#xff0c;那么作为一个Java工程师&#xff0c;应该如何利…

【Shell】mksh运行分析

mksh运行分析 Shell shell&#xff0c;壳子&#xff0c;即操作系统的壳子。这层壳子套在操作系统上&#xff0c;为用户提供与操作系统的交互手段。 操作系统的交互方式一般有&#xff0c;图形化交互(GUI)和命令行交付(CLI,command-line interface)。 套在操作系统上的壳子 …

虚拟机栈

虚拟机栈简介虚拟机栈的出现背景内存中的栈与堆虚拟机栈基本内容虚拟机栈的特点虚拟机栈的异常设置栈内存大小栈的存储单位栈中存储什么&#xff1f;栈运行原理栈帧的内部结构局部变量表认识局部变量表关于Slot的理解Slot代码示例Slot的重复利用静态变量与局部变量的对比补充说…

oracle安装教程

1安装和创建用户 1.1.安装以及常见问题 oracle安装教程 安装中 system密码改成root oracle卸载&#xff0c;除此之外清除C:\Program Files内的oracle 需要准备oracle安装包和plsql界面化操作工具 重装报错bug&#xff1a; plsql操作 plsql注册码 product code: ke4tv8t5jtxz…

java动态代理-面向切面代码样例

1.测试入口import java.lang.reflect.Proxy;/*** 面向切面测试* author epsoft-hy**/ public class test {public static void main(String[] args) {Class<?>[] cls {UserDao.class};//接口一个String classpath"util.aop.UserDaoImp";//访问类路径test2(tes…