malloc是如何分配内存|malloc(1)分配多大内存|free释放内存,会还给操作系统吗?

前言

大家好, 我jiantaoyab,这篇文章给大家介绍mallo和free面试中常问到的问题。

malloc是如何分配内存的?

如果用户分配的内存小于128KB,则通过brk()申请内存

如果用户分配的内存大于128KB,则通过mmap()申请内存

简化进程虚拟地址空间图

每一个进程中都有一个struct task_struct{}里面有一个内存指针指向进程的虚拟地址空间,在栈和堆区中间未分配区域称为文件映射区。

image-20240329221435432

通过代码验证

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{void* p = malloc(1024);printf("起始地址 : %p\n", p);while(1) sleep(1);return 0;
}

程序运行起来,查看到进程号,进入该进程号的目录下面

image-20240329222135989

用cat命令查看maps文件

image-20240329222304507

可以看到,申请出来的空间是在heap的上面一点点,是调用brk()申请出的内存空间。

那我们将申请的空间改大一点,再来验证一下

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{void* p = malloc(128 * 1024);printf("起始地址 : %p\n", p);while(1) sleep(1);return 0;
}  

image-20240329222900499

可以看到在64位的机器下,这个地址非常的大,刚刚能看到的heap也不见了,说明是通过mmap()申请内存。

malloc(1)会分配多大内存?

我们将用代码来验证,还是用上面的代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{void* p = malloc(1);printf("起始地址 : %p\n", p);while(1) sleep(1);return 0;
}

image-20240329223307601

申请出来空间的范围是00ff8000-01019000 = (2 1000)16 = (135168)10 / 1024 = 132kb,所以malloc(1)会申请出132kb的内存。

free释放内存,会归还给操作系统吗?

继续通过代码验证

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{void* p = malloc(1024);printf("起始地址 : %p\n", p);getchar();free(p);printf("free()!\n");while(1) sleep(1);return 0;
}

运行起来,分配了空间

image-20240329224155247

调用free,可以看到空间没有还给操作系统,这里是交给malloc去管理了

image-20240329224246130

把代码改大一点

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{void* p = malloc(1024 * 128);printf("起始地址 : %p\n", p);getchar();free(p);printf("free()!\n");while(1) sleep(1);return 0;
}

image-20240329224558338

可以看到,已经将空间归还给操作系统了。

总结

  1. malloc申请的空间小于128k,释放内存,不会还给操作系统由malloc内部管理起来
  2. malloc申请的空间大于等于128k,释放内存,还给操作系统

free函数如何知道释放多少内存?

查看glibc版本,通过https://ftp.gnu.org/gnu/glibc/下载

image-20240329224933360

下载下来后在malloc.c下面,能看到

image-20240329231249769

struct malloc_chunk {INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */struct malloc_chunk* fd;         /* double links -- used only if free. */struct malloc_chunk* bk;/* Only used for large blocks: pointer to next larger size.  */struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */struct malloc_chunk* bk_nextsize;
};

image-20240329231804633

INTERNAL_SIZE_T : size_t 64位机器下 8字节
prev_size: 上一个chunk的大小

size:当前块的大小,包括头部

当空闲的时候

fd:指向同一个bin中的下一个free chunk

bd:指向同一个bin中的前一个free chunk

free源代码

#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))
//通过偏移得到起始块的地址
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) //判断一个块是否使用
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
#define PREV_INUSE 0x1/* extract inuse bit of previous chunk */
#define prev_inuse(p)       ((p)->size & PREV_INUSE)__libc_free(void* mem)
{mstate ar_ptr;mchunkptr p;                          /* chunk corresponding to mem *///异常处理void (*hook) (__malloc_ptr_t, const __malloc_ptr_t)= force_reg (__free_hook);if (__builtin_expect (hook != NULL, 0)) {(*hook)(mem, RETURN_ADDRESS (0));return;}if (mem == 0)                              /* free(0) has no effect */return;p = mem2chunk(mem);if (chunk_is_mmapped(p))                       /* release mmapped memory. */{/* see if the dynamic brk/mmap threshold needs adjusting */if (!mp_.no_dyn_threshold&& p->size > mp_.mmap_threshold&& p->size <= DEFAULT_MMAP_THRESHOLD_MAX){mp_.mmap_threshold = chunksize (p);mp_.trim_threshold = 2 * mp_.mmap_threshold;}munmap_chunk(p);return;}ar_ptr = arena_for_chunk(p);_int_free(ar_ptr, p, 0);
}

free函数是通过struct malloc_chuck结构体中的size知道需要释放多少内存空间的。

free空指针会崩吗?

并不会

  if (mem == 0)                              /* free(0) has no effect */return;

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

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

相关文章

数据分析之POWER Piovt的KPI设置

内容总结&#xff1a; 1.两个表格关联不上&#xff1a;需要添加辅助列&#xff0c;建立关联 2.添加辅助列后还关联不上&#xff1a;将虚线变为实线 3.根据需求要增加一些度量值 4.设置KPI后&#xff0c;绝对值选1后设定百分比 5.在透视表里面加入KPI状态 导入所关联的数据后建立…

游戏领域AI智能视频剪辑解决方案

游戏行业作为文化创意产业的重要组成部分&#xff0c;其发展和创新速度令人瞩目。然而&#xff0c;随着游戏内容的日益丰富和直播文化的兴起&#xff0c;传统的视频剪辑方式已难以满足玩家和观众日益增长的需求。美摄科技&#xff0c;凭借其在AI智能视频剪辑领域的深厚积累和创…

SQLBolt,一个练习SQL的宝藏网站

知乎上有人问学SQL有什么好的网站&#xff0c;这可太多了。 我之前学习SQL买了本SQL学习指南&#xff0c;把语法从头到尾看了个遍&#xff0c;但仅仅是心里有数的程度&#xff0c;后来进公司大量的写代码跑数&#xff0c;才算真真摸透了SQL&#xff0c;知道怎么调优才能最大化…

SpringBoot登录校验(三)

​​​​​​​SpringBoot 登录认证&#xff08;一&#xff09;-CSDN博客 SpringBoot 登录认证&#xff08;二&#xff09;-CSDN博客 SpringBoot登录校验&#xff08;三&#xff09;-CSDN博客 前面我们介绍了传统的会话跟踪技术cookie和sesstion&#xff0c;本节讲解令牌技术…

Ubuntu20.04LTS+uhd3.15+gnuradio3.8.1源码编译及安装

文章目录 前言一、卸载本地 gnuradio二、安装 UHD 驱动三、编译及安装 gnuradio四、验证 前言 本地 Ubuntu 环境的 gnuradio 是按照官方指导使用 ppa 的方式安装 uhd 和 gnuradio 的&#xff0c;也是最方便的方法&#xff0c;但是存在着一个问题&#xff0c;就是我无法修改底层…

HarmonyOS实战开发-如何实现一个简单的电子相册应用开发

介绍 本篇Codelab介绍了如何实现一个简单的电子相册应用的开发&#xff0c;主要功能包括&#xff1a; 实现首页顶部的轮播效果。实现页面跳转时共享元素的转场动画效果。实现通过手势控制图片的放大、缩小、左右滑动查看细节等效果。 相关概念 Swiper&#xff1a;滑块视图容…

java多线程中的阻塞队列

一、普通不阻塞队列 还记得队列我们如何实现吗&#xff1f;我们用的是循环队列的方式&#xff0c;回一下&#xff1a; 描述&#xff1a;开始tail和head指针都指向最开始位置&#xff0c;往里面添加元素tail&#xff0c;出元素head 初始状态&#xff1a; put元素后状态 take…

账号微服务短信验证码发送工具单元测试

账号微服务短信验证码发送工具单元测试 注意sms的 app-code #----------sms短信配置-------------- sms:app-code: dd7829bedfaf4373875aa91abba82523template-id: JM1000372package net.xdclass.config;import org.springframework.context.annotation.Bean; import org.spri…

ROS 2边学边练(4)-- 何为主题(topics)

概念 主题是一种节点间的通信方式&#xff0c;某个节点充当发布特定&#xff08;主题&#xff09;消息&#xff08;数据&#xff09;的角色&#xff0c;另外一些节点则可以订阅接收该特定&#xff08;主题&#xff09;消息&#xff08;数据&#xff09;。两者&#xff0…

在ubuntu上搭建系统监控系统

大纲 数据生产方安装和运行验证 数据收集、存储和分发方下载和解压修改配置运行验证 数据消费方下载和运行验证新增数据源新增看板关联看板和数据源效果展现 参考资料 在一个监控系统中&#xff0c;一定会有“数据生产方”和“数据消费方”存在。“数据生产方”用于产出需要监控…

Android MediaRecorder

AndroidManifest.xml中添加权限标记 <uses-permission android:name"android.permission.RECORD_AUDIO"/> 动态添加权限MainActivity requestPermissions(new String[]{Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO},100); 创建MediaReco…

Flask学习(五):session相关流程

流程图如下图所示&#xff1a; 调用相关类如下图所示&#xff1a; 相关代码如下&#xff1a; from flask import Flask, sessionapp Flask(__name__)1. 加密会话数据&#xff1a;在 Flask 中&#xff0c;会话数据存储在客户端的 cookie 中。设置 app.secret_key 可以加密会话…

OLED模块

OLED模块 综述&#xff1a;本篇文章简要讲述了oled的定义&#xff0c;两种oled的引脚和接线情况、iic通讯协议、spi通讯协议、OLED代码引用和注意事项。 1.定义 OLED&#xff08;Organic Light-Emitting Diode&#xff09;模块是一种使用有机发光二极管作为显示元素的显示模…

DFS:二叉树的深搜与回溯

一、计算布尔二叉树的值 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public:bool evaluateTree(TreeNode* root) {if(root->leftnullptr) return root->val0?false:true; bool left evaluateTree(root->left);bool rightevaluateTree(root->rig…

1.1 单片机的概念

一,单片机的概念 单片机(Single-Chip Microcomputer),也被称为单片微控制器,是一种集成电路芯片。它采用超大规模集成电路技术,将具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、…

springcloud基本使用(搭建eureka服务端)

创建springbootmaven项目 next next finish创建成功 删除项目下所有文件目录&#xff0c;只保留pox.xml文件 父项目中的依赖&#xff1a; springboot依赖&#xff1a; <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-s…

Swift:“逻辑运算子“与“比较运算符“

1. 逻辑非 ! 逻辑非运算符 ! 是用于对布尔值取反的。当操作数为 true 时&#xff0c;! 将返回 false&#xff0c;而当操作数为 false 时&#xff0c;! 将返回 true。 let isTrue true let isFalse !isTrue // isFalse 现在是 false 2. 逻辑与 && 逻辑与运算符 &a…

爬取b站音频和视频数据,未合成一个视频

一、首先找到含有音频和视频的url地址 打开一个视频&#xff0c;刷新后&#xff0c;找到这个包&#xff0c;里面有我们所需要的数据 访问这个数据包后&#xff0c;获取字符串数据&#xff0c;用正则提取&#xff0c;再转为json字符串方便提取。 二、获得标题和音频数据后&…

linux基础命令篇:Linux基础命令讲解——文件浏览(cat、less、head、tail和grep)

Linux基础命令讲解——文件浏览&#xff08;cat、less、head、tail和grep&#xff09; 本文详细介绍Linux中的cat、less、head、tail和grep命令&#xff0c;这些命令在日常工作中非常实用&#xff0c;以下是关于这些命令的详细介绍&#xff1a; 1. cat命令&#xff1a;用于查看…

JUC:synchronized优化——锁的升级过程(偏向锁->轻量级锁->重量级锁)以及内部实现原理

文章目录 锁的类型轻量级锁重量级锁自旋优化偏向锁偏向锁的细节偏向锁的撤销批量重偏向批量撤销锁消除 锁的类型 重量级锁、轻量级锁、偏向锁。 加锁过程&#xff1a;偏向->轻量级->重量级 轻量级锁 轻量级锁的使用场景&#xff1a;如果一个对象虽然有多线程要加锁&am…