【深度解刨C语言】内存管理(详)


文章目录

  • 前言
  • 一.动态内存
    • 1.动态内存的用处
    • 2.内存的布局
        • 简单证明内存布局
        • 栈向下生长的证明
        • 堆向上增长的证明
    • 3.malloc与free进一步理解
  • 总结

前言

前提:

  • 内存有基本的认识
  • 内存函数基本的了解

如果你对内存与内存函数太不清楚可以看:动态内存管理

目标:

  • 为什么要用动态内存?
  • 内存的布局
  • free只有一个参数,怎么将内存函数在堆上开辟的空间进行释放?

一.动态内存

1.动态内存的用处

int main()
{
	char arr[1024*1024]={0};
	return 0;
}

结果:
代码异常退出
在这里插入图片描述
当我们在栈上开辟1MB的大小的空间时超出了堆栈的大小

注意:
堆栈==栈
堆栈!=堆
本文的堆是程序的空间,而在数据结构中,堆是一种完全二叉树的非线性结构!

结论:

  • 栈的空间很小,大约为1MB。
  • 堆的空间很大,大约为2GB
  • 因此:动态内存,是为了满足更大数据的需求!
  • 为什么要用动态内存?

2.内存的布局

在这里插入图片描述

  • 这里的储存空间并不是内存!而是进程虚拟地址空间
  • 补充:具体涉及到操作系统的知识,只需了解即可!

简单证明内存布局

  • 这里只证明除去代码区之外的部分
#include<stdio.h>
#include <stdlib.h>
int g_val;//初始化的全局变量
int g_val_1 = 0;//未初始化的全局变量
int main()
{

	int a = 0;//栈区的变量
	int* arr = (int*)malloc(sizeof(int) * 20);//将堆区的地址赋值给arr
	char* str = "abcdef";//将字符常量区的地址赋值跟str
	
	printf("字符常量区:            %p\n", str);
	printf("初始化的全局变的内存:  %p\n", &g_val_1);
	printf("未初始化全局变量的内存:%p\n", &g_val);
	printf("堆区:                  %p\n", arr);
	printf("栈区:                  %p\n", &a);

	free(arr);
	arr = NULL;
	return 0;
}
  1. 方法:假设法证明
  2. 结论成立:从字符常量区的变量的地址到栈区的地址呈现增大趋势

结果:
在这里插入图片描述
结论:假设成立,结论成立!

栈向下生长的证明

同理

  • 只需证明: 不断开辟变量,地址呈现减小的趋势
#include<stdio.h>

int main()
{
	
	int a = 0;
	int b = 0;
	int c = 0;
	int d = 0;
	printf("a:%p\n", &a);
	printf("b:%p\n", &b);
	printf("c:%p\n", &c);
	printf("d:%p\n", &d);

	return 0;
}

结果:
在这里插入图片描述
结论:假设成立,结论成立!

堆向上增长的证明

同理

  • 只需证明: 不断开辟变量,地址呈现增大的趋势
  • 注意:这里开辟的空间要尽可能大
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* a = (int*)malloc(sizeof(int) * 1024);
	int* b = (int*)malloc(sizeof(int) * 1024);
	int* c = (int*)malloc(sizeof(int) * 1024);
	int* d = (int*)malloc(sizeof(int) * 1024);

	printf("%p\n", a);
	printf("%p\n", b);
	printf("%p\n", c);
	printf("%p\n", d);

	free(a);
	free(b);
	free(c);
	free(d);

	a = NULL;
	b = NULL;
	c = NULL;
	d = NULL;

	return 0;
}

结果:
在这里插入图片描述
结论:假设成立,结论成立!

3.malloc与free进一步理解

疑问产生:

  • free只有一个参数怎么准确的释放目标空间
  • malloc只开辟了我们想要的空间吗?

为了解决这两个问题,那我们调试走起!

调试代码:

#include<stdio.h>
#include<stdlib.h>
int main()
{

	char* arr = (char*)malloc(sizeof(char) * 10);
	if (arr == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
	free(arr);
	arr = NULL;
	return 0;
}

VS2019下调试
第一步:打开内存窗口
在这里插入图片描述
第二步:F9打断点
在这里插入图片描述
第三步:按F5走到断点处
第四步:在内存窗口输入arr加回车跳转到目标内存
在这里插入图片描述

假设:malloc只开辟这段空间,那么free只释放这段空间。
带着假设继续往下去:
第五步:按一下F10
在这里插入图片描述

很显然并不是只释放了这段空间。
因此:

  • malloc并不是只开辟指定的空间大小
  • free是通过malloc多开辟的空间来获取要释放空间的大小
    图解:
    在这里插入图片描述
    我们可以理解:
  • free传入arr,向上访问可以知道malloc空间的准确大小,以及相关信息。
  • 因此:free只传入一个参数即可释放开辟空间

疑问:那干脆数据都放在堆上算了,要栈有何用?

  • 假设数据很小——1字节
  • malloc开辟不止开辟1字节,还有相关信息(远大于1字节)
  • 这样空间利用率极低,不如在栈上开辟!
  • free只有一个参数,怎么将内存函数在堆上开辟的空间进行释放?

总结

文章不好,请不要点赞!

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

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

相关文章

我体验了首个接入GPT-4的代码编辑器,太炸裂了

最近一款名为Cursor的代码编辑器已经传遍了圈内&#xff0c;受到众多编程爱好者的追捧。 它主打的亮点就是&#xff0c;通过 GPT-4 来辅助你编程&#xff0c;完成 AI 智能生成代码、修改 Bug、生成测试等操作。 确实很吸引人&#xff0c;而且貌似也能大大节省人为的重复工作&…

vue尚品汇商城项目-day04【29.加入购物车操作(难点)】

文章目录29.加入购物车操作&#xff08;难点&#xff09;29.1加入购物车按钮29.2addCartSuce29.3购物车29.3.1 向服务器发送ajax请求&#xff0c;获取购物车数据29.3.2UUID临时游客身份29.3.3动态展示购物车29.4修改购物车产品的数量&#xff08;需要发请求&#xff1a;参数理解…

203. 移除链表元素

1、题目 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5]示例 2&#xff1a; 输入&…

File 类的用法和 InputStream, OutputStream,System 类的用法

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

Typescript学习笔记(一)

什么是TypeScript? TypeScript 是添加了类型系统的 JavaScript&#xff0c;适用于任何规模的项目。 TypeScript 是一门静态类型、弱类型的语言。 安装TypeScript npm install -g typescript编译 tsc hello.tsTypeScript 只会在编译时对类型进行静态检查&#xff0c;如果发…

iOS 内存管理机制与原理

内存分区 内存一般分为五大区&#xff1a;栈区、堆区、常量区、全局区、代码区。如图 1.栈区 是由编译器自动分配并释放的&#xff0c;主要用来存储局部变量、函数的参数等&#xff0c;是一块连续的内存区域&#xff0c;遵循先进后出&#xff08;FILO&#xff09;原则。一般在…

WebAssembly 助力云原生:APISIX 如何借助 Wasm 插件实现扩展功能?

本文将介绍 Wasm&#xff0c;以及 Apache APISIX 如何实现 Wasm 功能。 作者朱欣欣&#xff0c;API7.ai 技术工程师 原文链接 什么是 Wasm Wasm 是 WebAssembly 的缩写。WebAssembly/Wasm 是一个基于堆栈的虚拟机设计的指令格式。 在 Wasm 未出现之前&#xff0c;浏览器中只能…

Hadoop(伪分布式)+Spark(local模式)搭建Hadoop和Spark组合环境

一、安装Hadoop环境使用Ubuntu 14.04 64位 作为系统环境&#xff08;Ubuntu 12.04&#xff0c;Ubuntu16.04 也行&#xff0c;32位、64位均可&#xff09;&#xff0c;请自行安装系统。Hadoop版本: Hadoop 2.7.4创建hadoop用户如果你安装 Ubuntu 的时候不是用的 "hadoop&qu…

研究的艺术 (The craft of research) 读书笔记

前言 如果你对这篇文章感兴趣&#xff0c;可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」&#xff0c;查看完整博客分类与对应链接。 对于研究者而言&#xff0c;写作是一件很重要的事&#xff0c;好的写作不仅能让更多人愿意读&#xff0c;获得更大影响力&…

Windows系统配置SSH服务

1.安装OpenSSH 打开【设置】-【应用】 选择【管理可选功能】 点击【添加可选功能】 选择【OpenSSH 服务端】&#xff0c;切记不是【OpenSSH 客户端】&#xff08;如果安装一个不行&#xff0c;就都安装&#xff0c;我都安装了可以用&#xff09;&#xff0c;然后点击下载即可 …

ERP系统如何让项目管理更轻松?

项目管理是许多企业的首要任务&#xff0c;通常有一个ERP系统来协助他们。然而&#xff0c;一些企业仍然没有意识到&#xff0c;ERP解决方案可以使他们的项目管理更容易。项目管理需要有一个目标&#xff0c;并在你朝着完成项目前进的过程中控制变量&#xff0c;而ERP系统指导你…

成都北大青鸟怎么样?

对于任何一个培训机构的了解大概的流程是&#xff1a;听说名字——网上搜索&#xff0c;可以看到机构官网&#xff0c;也会看到机构广告&#xff0c;当然也会看到各种有好有坏的评论&#xff0c;到这里会对机构形成初印象&#xff1b;然后如果身边有培训出身的小伙伴会去询问对…

【C语言进阶:自定义类型详解】联合(共用体)

本节重点内容&#xff1a; 联合类型的定义联合的特点联合大小的计算⚡联合类型的定义 联合也是一种特殊的自定义类型这种类型定义的变量也包含一系列的成员&#xff0c;特征是这些成员公用同一块空间&#xff08;所以联合也叫共用体&#xff09;。 为了方便大家理解举个例子…

Java 网络编程之NIO(ByteBuffer)

在 Java NIO 中&#xff0c;ByteBuffer 是用于存储和传输数据的一种数据结构。它提供了高效的数据存储和读取能力&#xff0c;使得 Java NIO 能够高效地处理大量的数据输入输出。 ByteBuffer 的作用包括以下几个方面: 存储数据:ByteBuffer 可以存储任意长度的数据&#xff0c;…

Elasticsearch 8.X 如何基于用户指定 ID 顺序召回数据?

1、实战问题如何根据输入的id 的顺序输出结果&#xff0c;id 个数有500个&#xff0c;还有分页&#xff1f;问题来源&#xff1a;https://t.zsxq.com/0cdyq7tzr2、方案探讨2.1 Elasticsearch 默认排序机制在 Elasticsearch 中&#xff0c;如果未指定排序规则&#xff0c;检索结…

Linux下实现的 HTTP 服务器

项目功能&#xff1a;&#xff08;1&#xff09;能接收客户端的GET请求&#xff1b;&#xff08;2&#xff09;能够解析客户端的请求报文&#xff0c;根据客户端要求找到相应的资源&#xff1b;&#xff08;2&#xff09;能够回复http应答报文&#xff1b;&#xff08;3&#x…

数据结构和算法学习记录——设计循环队列(数组实现循环队列)核心思路、题解过程、完整题解

目录 题目描述 题目示例 核心思路 链表实现 数组实现 重点 题解过程 结构体类型定义 创建一个循环队列并初始化 判断循环队列为空或为满 入队列函数 出队列函数 取队头数据 取队尾数据 销毁循环队列 完整题解 题目来源&#xff1a;力扣 题目描述 设计你的…

Sentinel滑动时间窗限流算法原理及源码解析(下)

文章目录对统计数据如何使用获取之前统计好的数据对统计数据如何使用 流控快速失败 获取之前统计好的数据

SpringBoot 项目的创建与启动

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

iosApplePay

1、Apple Pay 接入工程 - 简书 // 设置币种、国家码及merchant标识符等基本信息 PKPaymentRequest *payRequest [[PKPaymentRequest alloc]init]; payRequest.countryCode "CN"; //国家代码 payRequest.currencyCode "CNY"; //RMB的币种代码 …