嵌入式Linux系统编程 — 5.6 Linux系统申请堆内存

目录

1 内存概念

1.1 什么是堆内存

1.2 内存分布

2 malloc、free在堆上分配与释放内存

2.1 malloc函数

2.2 free函数

2.3 示例程序

注意事项:

3 calloc分配内存

3.1 calloc函数介绍

3.2 示例程序

4 分配对齐内存

4.1 函数介绍

4.2 示例程序


1 内存概念

1.1 什么是堆内存

堆内存(Heap Memory)是计算机程序中用于动态内存分配的内存区域。与栈内存(Stack Memory)不同,堆内存的分配和释放不是自动的,而是由程序员通过调用内存分配函数(如C语言中的 mallocfree)来控制的。

1.2 内存分布

  • 栈(Stack):用于存储局部变量和函数调用信息,向高地址增长。
  • 堆(Heap):用于动态内存分配,向低地址增长。
  • 全局/静态区(Global/Static Area):存储全局变量和静态变量,生命周期与程序相同。
  • 常量区(Constant Area):用于存储程序中的常量数据,这些数据在整个程序的生命周期内保持不变,并且在程序的多个地方可能被引用。C语言可以使用 const 关键字来定义常量。
  • 代码区(Code Area):存储程序的指令。
  • 其他:可能还包括文件缓冲区、环境变量等。

2 malloc、free在堆上分配与释放内存

2.1 malloc函数

Linux C 程序当中一般使用 malloc()函数为程序分配一段堆内存,而使用 free()函数来释放这段内存,先来看下 malloc()函数原型,如下所示:

#include <stdlib.h>void *malloc(size_t size);
  • size: 堆上分配一块大小为 size 字节的内存区域。
  • 返回值: 返回指向这块内存的指针;如果分配失败(通常是由于内存不足),它会返回 NULL

2.2 free函数

free 用于释放之前通过 malloccalloc 或 realloc 等函数分配的内存。这块内存空间在函数执行完成后不会释放,它们的值是未知的,所以通常需要程序员对 malloc()分配的堆内存进行内存释放操作。通常使用 free()函数释放堆内存, free()函数原型如下所示:

#include <stdlib.h>void free(void *ptr);
  • ptr: 指向需要被释放的堆内存对应的指针。
  • 返回值: 无返回值

2.3 示例程序

下面是一个简单的C语言程序示例,演示了如何使用 mallocfree 进行动态内存分配和释放:

#include <stdio.h>
#include <stdlib.h> // 包含malloc和free函数的头文件int main() 
{int n; // 定义一个整数变量,用于存储数组的大小printf("Enter the size of the array you want to create: ");scanf("%d", &n); // 从用户那里获取数组的大小// 使用malloc动态分配一个整数数组的内存int *array = (int *)malloc(n * sizeof(int));if (array == NULL) {// 如果分配失败,打印错误信息并退出程序fprintf(stderr, "Error: Memory allocation failed!\n");return 1;}// 初始化数组for (int i = 0; i < n; i++) {array[i] = i * i; // 例如,将数组元素设置为其索引的平方}// 打印数组内容printf("Array elements:\n");for (int i = 0; i < n; i++) {printf("%d ", array[i]);}printf("\n");// 使用完数组后,使用free释放分配的内存free(array);// 再次打印数组内容,此时应该输出未定义的值printf("Attempt to print array after freeing memory:\n");for (int i = 0; i < n; i++) {printf("%d ", array[i]); // 此处访问已释放的内存,可能导致未定义行为}printf("\n");return 0;
}

程序通过 malloc 函数动态分配一个整数数组的内存,大小由用户输入决定,用 free 函数释放之前分配的内存。尝试再次打印数组内容,这将导致未定义行为,因为内存已经被释放。运行结果如下:

注意事项:

  • 释放内存后,不应该再访问该内存区域,否则可能导致程序崩溃或产生不可预测的结果。
  • 确保在使用完动态分配的内存后调用 free 函数,以避免内存泄漏。

3 calloc分配内存

3.1 calloc函数介绍

alloc 与 malloc 类似,但有一些关键的区别。calloc 用于分配足够存储一个指定数量的对象的内存块,并且将分配的内存初始化为0。这种分配对于需要从零开始的数组或数据结构非常有用。calloc 函数原型:

#include <stdlib.h>void *calloc(size_t num, size_t size);
  • num:要分配的对象的数量。
  • size:每个对象的大小(以字节为单位)。
  • 返回值:如果内存分配成功,calloc 返回指向分配内存的指针,并且这块内存的所有字节都被初始化为零。如果内存分配失败,calloc 返回 NULL

3.2 示例程序

下面是 calloc 函数的示例程序,程序会动态分配一个整数数组的内存,并初始化所有元素为零,然后打印数组的内容,最后释放内存。

#include <stdio.h>
#include <stdlib.h>int main() 
{int n; // 数组的大小printf("Enter the size of the array you want to create: ");scanf("%d", &n); // 从用户那里获取数组的大小// 使用calloc动态分配一个整数数组的内存,并初始化为零int *array = (int *)calloc(n, sizeof(int));if (array == NULL) {// 如果分配失败,打印错误信息并退出程序fprintf(stderr, "Error: Memory allocation failed!\n");return 1;}// 打印数组内容,此时所有元素都是0printf("Array elements (initialized to zero):\n");for (int i = 0; i < n; i++) {printf("%d ", array[i]);}printf("\n");// 可以选择在这里修改数组的某些元素// 例如:array[0] = 1; // 将第一个元素设置为1// 使用完数组后,使用free释放分配的内存free(array);// 再次尝试访问数组内容,将会导致未定义行为// printf("Attempt to print array after freeing memory: %d\n", array[0]);return 0;
}

运行结果如下 

4 分配对齐内存

4.1 函数介绍

C 函数库中还提供了一系列在堆上分配对齐内存的函数,对齐内存在某些应用场合非常有必要,常用于分配对其内存的库函数有: posix_memalign()、 aligned_alloc()、 memalign()、valloc()、 pvalloc(),如果不需要特定的对齐,通常使用 malloc()calloc() 就足够了。它们的函数原型如下所示:

posix_memalign()函数:分配一块至少 size 大小的内存,并确保其地址是 alignment 的倍数。如果成功,返回0;如果失败,返回一个错误码。

#include <stdlib.h>int posix_memalign(void **ptr, size_t alignment, size_t size);
  • ptr:指向一个 void* 的指针,函数将通过这个指针返回分配的内存的地址。
  • alignment:所需的内存对齐字节数,必须是2的幂,也必须是 sizeof(void*) 的倍数。
  • size:要分配的内存大小(以字节为单位)。
  • 功能:

aligned_alloc()函数:分配一块至少 size 大小的内存,并且返回的内存地址是 alignment 的倍数。如果分配成功,返回指向分配内存的指针;如果失败(如对齐要求无法满足),返回 NULL

#include <stdlib.h>void *aligned_alloc(size_t alignment, size_t size);
  • alignment:内存对齐的字节数,必须是2的幂。
  • size:要分配的内存大小。

memalign()函数:与 posix_memalign 类似,分配一块至少 size 大小的内存,memalign()与 aligned_alloc()参数是一样的,它们之间的区别在于:对于参数 size 必须是参数 alignment
的整数倍这个限制条件, memalign()并没有这个限制条件。

#include <malloc.h>void *memalign(size_t alignment, size_t size);
  • alignment:所需的内存对齐字节数。
  • size:要分配的内存大小。

valloc()函数:分配一块至少 size 大小的内存,并且地址是页面大小的整数倍。页面大小通常为4096字节。

#include <stdlib.h>void *valloc(size_t size);
  • size:要分配的内存大小。

pvalloc()函数:分配足够大的内存,以确保至少有一个页面,并且返回的内存地址是页面大小的整数倍。分配的内存大小将是 size 的下一个页面大小的倍数。

#include <malloc.hvoid *pvalloc(size_t size);
  • size:要分配的内存大小,必须是非负整数,并且足够大,以确保分配的内存至少有一个页面。

4.2 示例程序

以下是使用 posix_memalign()aligned_alloc()memalign()valloc()pvalloc() 函数的示例程序。程序使用这些函数来分配内存,并打印出分配的内存地址,以展示内存对齐的效果。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <malloc.h>int main() 
{void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;size_t size = 1024; // 分配大小为1KB的内存size_t alignment = 64; // 指定内存对齐到64字节边界// 使用posix_memalign分配内存if (posix_memalign(&ptr1, alignment, size) != 0) {perror("posix_memalign failed");return 1;}printf("Memory allocated by posix_memalign: %p\n", ptr1);// 使用aligned_alloc分配内存ptr2 = aligned_alloc(alignment, size);if (ptr2 == NULL) {perror("aligned_alloc failed");return 1;}printf("Memory allocated by aligned_alloc: %p\n", ptr2);// 使用memalign分配内存(GNU扩展)ptr3 = memalign(alignment, size);if (ptr3 == NULL) {perror("memalign failed");return 1;}printf("Memory allocated by memalign: %p\n", ptr3);// 使用valloc分配内存ptr4 = valloc(size);if (ptr4 == NULL) {perror("valloc failed");return 1;}printf("Memory allocated by valloc: %p\n", ptr4);// 使用pvalloc分配内存ptr5 = pvalloc(size);if (ptr5 == NULL) {perror("pvalloc failed");return 1;}printf("Memory allocated by pvalloc: %p\n", ptr5);// 释放分配的内存free(ptr1);free(ptr2);free(ptr3); // 注意:memalign分配的内存需要用free释放free(ptr4);free(ptr5); // 注意:pvalloc分配的内存需要用free释放return 0;
}

运行结果如下:

运行结果可以看到每个函数分配的内存地址,地址显示了不同函数分配内存时对齐方式的差异。下面是对每个函数分配结果的分析:

  • posix_memalign:分配的内存地址是 0x5574280be040,地址的最低几位数字(040)显示了内存对齐的情况,地址是按照16字节对齐的(因为040是16的倍数)。
  • aligned_alloc:分配的内存地址是 0x5574280beb80,地址的最低几位数字(b80)表明内存也是按照16字节对齐的。
  • memalign:分配的内存地址是 0x5574280bf000,地址以 000 结尾,表明内存是按照页面大小(通常是4096字节或4KB)对齐的。
  • valloc:分配的内存地址是 0x5574280c0000,地址以 0000 结尾,进一步证实了 valloc 函数分配的内存确实是按照页面大小对齐的。
  • pvalloc:分配的内存地址是 0x5574280c1000。同样以 000 结尾,表明这也是页面大小对齐的内存。

 

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

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

相关文章

推荐下载:Windows11 23H2专业工作站版!高效办公首选!

今天系统之家小编给需要高性能计算能力、高级安全功能和专业级应用程序支持的用户推荐一款操作系统&#xff0c;那就是Windows11 23H2专业工作站版系统&#xff0c;该系统经过优化&#xff0c;具有更强的数据处理能力和更高的安全性&#xff0c;还具有出色的兼容性&#xff0c;…

1分钟了解LangChain4j是什么?

一: LangChain4j介绍 LangChain现在仅支持​ Python语言与Javascript语言&#xff0c; 而LangChain4J就是属于Java版本的 LangChain&#xff0c;它的目的也是简化LLM&#xff08;大语言模型&#xff09;与Java应用程序的集成。 大模型时代&#xff0c;如何将大模型能力和传统应…

如何使用Xcode查看iOS APP客户端日志

在测试iOS app过程中&#xff0c;能够有效查看和分析客户端日志是至关重要的。不论是定位crash还是解决复杂的逻辑错误&#xff0c;日志都扮演了不可或缺的角色。Apple的Xcode提供了一个强大的工具集&#xff0c;帮助测试同学有效地进行日志查看和分析。本文将逐步指导如何使用…

深入剖析:Postman报错排查全攻略

&#x1f50d; 深入剖析&#xff1a;Postman报错排查全攻略 Postman作为API开发和测试的强大工具&#xff0c;虽然功能强大&#xff0c;但在使用过程中难免会遇到各种报错问题。本文将带领你深入排查Postman中的常见错误&#xff0c;提供全面的解决方案&#xff0c;让你能够快…

ubuntu语音库ALSA报错具体原因

在ubuntu中使用pyaudio或portaudio时总会有下面的提示&#xff0c;不胜其烦。 ALSA lib pcm_dsnoop.c:612:(snd_pcm_dsnoop_open) unable to open slave ALSA lib pcm_dmix.c:1018:(snd_pcm_dmix_open) unable to open slave ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unkn…

PyTorch学习之torch.matmul函数

PyTorch学习之torch.matmul函数 一、简介 torch.matmul 用于两维或更高维张量的矩阵乘法操作。它支持广播机制&#xff0c;并且能够处理不同形状和维度的张量&#xff0c;适用于广泛的应用场景。 二、语法 torch.matmul 函数的基本语法如下&#xff1a; torch.matmul(inpu…

论文笔记:MobilityGPT: Enhanced Human MobilityModeling with a GPT mode

1 intro 1.1 背景 尽管对人类移动轨迹数据集的需求不断增加&#xff0c;但其访问和分发仍面临诸多挑战 首先&#xff0c;这些数据集通常由私人公司或政府机构收集&#xff0c;因此可能因泄露个人敏感生活模式而引发隐私问题其次&#xff0c;公司拥有的数据集可能会暴露专有商…

C++纯虚函数的理解,纯虚函数和派生类的关系。

在 C 中&#xff0c;纯虚函数&#xff08;pure virtual function&#xff09;是一种特殊的虚函数&#xff0c;它在基类中没有实现&#xff0c;只定义了一个接口&#xff0c;要求派生类必须提供具体实现。纯虚函数的定义方式在接口设计和多态性中非常有用。 纯虚函数的定义和语…

PAI3D: Painting Adaptive Instance-Prior for 3D Object Detection论文讲解

PAI3D: Painting Adaptive Instance-Prior for 3D Object Detection论文讲解 1. 引言2. PAI3D框架2.1 Instance Painter2.2 Adaptive Projection Refiner2.3 Fine-granular Detection Head 3. 实验结果3.1 消融实验 1. 引言 3D目标检测对于自动驾驶来说是一个非常重要的模块&a…

如何现代的编译和安装内核

前言&#xff1a;本文是在阅读书目时找到了一篇非常高质量的文章。的原文是英文&#xff0c;现在我自己手头翻译了一下&#xff0c;发布到这里。 原文连接&#xff1a;How to compile a Linux kernel in the 21st century | Opensource.com 目录 更新内核的现代方法 安装内…

C++知识点总结全系列 (05):IO 类的详细总结和分析

1、基类 istream 和 ostream (1)istream A.What 输入流的抽象类&#xff0c;是所有输入流类的基类 B.Why&#xff08;输入流的作用&#xff09; 用于从数据源&#xff08;如文件、标准输入设备等&#xff09;读取数据 (2)ostream A.What 输出流的抽象类&#xff0c;是所有输…

grpc学习golang版( 六、服务器流式传输 )

系列文章目录 第一章 grpc基本概念与安装 第二章 grpc入门示例 第三章 proto文件数据类型 第四章 多服务示例 第五章 多proto文件示例 第六章 服务器流式传输 第七章 客户端流式传输 第八章 双向流示例 文章目录 一、前言二、定义proto文件三、拷贝任意文件进项目四、编写serve…

复制完若依后,idea没有maven窗口

右击项目 添加框架 添加maven框架就可以了

使用Java实现实时数据处理系统

使用Java实现实时数据处理系统 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 引言 在当今信息爆炸的时代&#xff0c;实时数据处理系统变得越来越重要。无论…

protobuf C++通过协议名获取协议类实例

当知道协议名称时&#xff0c;要获取类的实例有很多种方法 方案一&#xff1a;通过协议名和类实例化绑定&#xff0c;注册到变量&#xff0c;使用的时候再通过名字查找 方案二&#xff1a;通过protobuf自带的查找接口实现&#xff0c;代码如下&#xff1a; #include <iostr…

大数据开发中的数据倾斜问题

数据倾斜是大数据开发中常见的性能瓶颈&#xff0c;了解其原因并采取有效的解决方案对系统性能至关重要。本文将从数据倾斜的影响、解决方法及示例代码等方面进行详细讨论。 目录 1. 数据倾斜的影响2. 解决数据倾斜的方法调整分区键预聚合倾斜处理逻辑 3. 进一步解决数据倾斜的…

vue3.0 + vant实现下拉刷新上拉加载

在vue中使用vant组件库有个van-pull-refresh下拉组件&#xff0c;配合van-list列表组件实现页面的下拉刷新和上拉加载&#xff0c;原理简单&#xff0c;适用场景在列表页面内容展示。 下拉刷新 PullRefresh 实现下拉刷新的效果。 PullRefresh组件中的searchRefreshing属性&…

51单片机嵌入式开发:STC89C52环境配置到点亮LED

STC89C52环境配置到点亮LED 1 环境配置1.1 硬件环境1.2 编译环境1.3 烧录环境 2 工程配置2.1 工程框架2.2 工程创建2.3 参数配置 3 点亮一个LED3.1 原理图解读3.2 代码配置3.3 演示 4 总结 1 环境配置 1.1 硬件环境 硬件环境采用“华晴电子”的MINIEL-89C开发板&#xff0c;这…

安卓app开发-基础-本地环境安装android studio且配置参数

安卓app开发-基础-本地环境安装android studio且配置参数&#xff01;今天为大家介绍一下&#xff0c;如何在自己本地电脑安装android ,studio和启动一个简单的java版本的项目。 第一步&#xff0c;去下面的地址&#xff0c;下载一个安装文件。 地址&#xff1a;AndroidDevToo…

root密码忘了怎么办(从系统引导过程解决)

目录 1.Linux系统密码忘记 2.系统引导过程 2.1 systemd 2.2 GRUB和GRUB2 2.3 运行级别 3.修复MBR扇区故障和GRUB引导故障 3.1 MBR扇区故障 3.2 GRUB引导故障 1.Linux系统密码忘记 我们在生活中经常遇到这类困扰&#xff0c;就是某个账号还是账户密码忘了&#xff0c;这…