C-内存管理

article/2025/10/1 7:29:27

内存管理

堆,栈,静态区

c程序地址空间分布规则:

栈是从高地址向低地址延伸的,后创建的变量,后入栈,那么地址就越小.

image-20230512123023817

静态变量,作用域不变,声明周期发生改变.本质原因是存储位置发生改变.编译器编译的时候放到了全局数据区.

image-20230512122920529

#include<stdio.h>
#include<stdlib.h>
int g_val2;
int g_val1=10;int main()
{int x=10;static int y=10;printf("代码区:%p\n",main);const char* str="hello yuanwei";printf("字符常量区:%p\n",str);printf("已初始化常量区:%p\n",&g_val1);printf("未初始化常量区:%p\n",&g_val2);char *p1=(char*)malloc(sizeof(char)*10);char *p2=(char*)malloc(sizeof(char)*10);char *p3=(char*)malloc(sizeof(char)*10);printf("堆区:%p\n",p1);printf("堆区:%p\n",p2);printf("堆区:%p\n",p3);printf("栈区:%p\n",&str);printf("栈区:%p\n",&p1);printf("x :%p\n",&x);printf("y:%p\n",&y);free(p1);free(p2);free(p3);
}

动态内存

动态内存开辟
#define N 10
int main()
{int* p = (int*)malloc(sizeof(int) * N);if (NULL == p){perror("malloc fail\n");exit(1);}for (int i = 0; i < N; i++){*(p + i) = i;}free(p);//堆空间申请的内存不要忘记释放return 0;
}
为什么要有动态内存

栈空间有限,申请不了大量内存空间.在技术方面,普通的空间申请,都是在全局或者栈区,全局一般不太建议大量使用,而栈空间有限,那么如果一个应用需要大量的内存空间的时候,需要通过申请堆空间来支持基本业务 .

在应用方面,程序员很难一次预估好自己总共需要花费多大的空间。想想之前我们定义的所有数组,因为其语法约束,我们必须得明确"指出"空间大小.但是如果用动态内存申请(malloc),因为malloc是函数,而函数就可以传参,也就意味着,我们可以通过具体的情况,对需要的内存大小进行动态计算,进而在传参申请,提供了很大的灵活性.

指针合法性

指针合法:能够被用户直接使用的,应用层面解决的.指针如果有具体指向(包含野指针),对应合法性我们是无法验证的,确认指针具体值得合法性,不是用户能做到的.

  1. 所有的指针,如果没有被直接使用,必须设置为NULL(编程规范)
  2. 函数内部,要验证指针的合法性,本质是验证指针!=NULL

系统提供检测指针是否合法的宏assert();如果内部条件不满足则中断运行,调试代码时用.assert()也无法检查野指针(随机值),语言层面是无法解决系统层面的问题的.

将开辟的空间初始化不是必须的,但是推荐.memset()

内存越界

在遍历内存空间的时候越界一些不一定会报错.并不是所有的严重问题都会显示出来.

内存泄漏

申请内存不释放.

  • 如果程序退出了,内存泄漏还存在吗?不在

  • 什么样的程序最怕内存泄漏?永远不会退出的程序(操作系统,杀毒软件,服务器程序(24小时在线))

free

只知道堆空间的起始地址,并没有告诉他要释放多少字节.

释放的字节数比10字节要多,说明最开始申请的字节就比10字节多.

image-20230513212842321

实际malloc申请空间时,系统给你的其实更多.多出来的部分就是记录这次申请的更详细的信息(内存级cookie信息)

  • 所以申请堆空间,是申请大空间更好,降低了cookie所占的比率.

  • 释放之后堆空间指针并不会被设置为NULL.

free理解

image-20230514092119567

经发现,堆空间释放前后,栈中的指针变量的值并没有被设置为NULL.释放后的空间也不能再被使用.

  • 那么所谓的释放究竟是什么?

free是在取消地址p和空间的关系,p里面的地址值可以相同但是不可再访问空间.关系也是需要用数据去维护的.

C中动态内存“管理”体现在哪

内存管理的本质其实是:空间什么时候申请,申请多少,什么时候释放,释放多少的问题。

  1. 场景:C的内存管理工作是由程序员决定的,而程序员什么时候申请,申请多少,什么时候释放,释放多少都是有场景决定的(比如上面的链表操作),而大部分书中,是讲具体操作,很少有场景,所以管理工作体现的并不直观。不过我们现在能理解即可。
  2. 其他高级语言:像java这样的高级语言,语言本身自带了内存管理,所以程序员只管使用即可。换句话说,内存管理工作,程序员是不用关心的。但是C是较为底层的语言,它的内存管理工作是暴露给程序员的,从而给程序员提供了更多的灵活性,不过,管理工作也同时交给了程序员.

链表测试:

image-20230514095718125

#define N 10
typedef struct Node
{int data;struct Node* next;
}Node_t;Node_t* AllocNode(int data)
{Node_t* node = (Node_t*)malloc(sizeof(Node_t));if (node == NULL){perror("malloc failed\n");exit(1);}node->data = data;node->next = NULL;return node;
}
void InsertNode(Node_t* head, int x)
{assert(head);Node_t* node = AllocNode(x);node->next = head->next;head->next = node;
}
void ShowList(Node_t* cur)
{assert(cur);cur = cur->next;while (cur){printf("%d ",cur->data);cur = cur->next;}printf("->NULL\n");
}
void DeleteNode(Node_t* head)
{assert(head);Node* p = head->next;head->next = p->next;free(p);p = NULL;
}
int main()
{Node_t* head = AllocNode(0);printf("插入测试开始:...\n");for (int i = 1; i <= N; i++){InsertNode(head,i);ShowList(head);Sleep(1000);}printf("删除测试开始:...\n");for (int i = 1; i <= N; i++){DeleteNode(head);ShowList(head);Sleep(1000);}system("pause");return 0;
}

http://chatgpt.dhexx.cn/article/LqU1Hbjp.shtml

相关文章

内存控制器(以位宽为16的NOR FLASH举例)

CPU 执行的指令&#xff1a; “ldr r0,[某个地址 A]”&#xff0c;ldr 是装载 4个字节&#xff0c;这是从这个地址里读取某个数据存到 r0 里去。 A 地址的 1 字节数据。A1 地址的 1 字节数据。A2 地址的 1 字节数据。A3 地址的 1 字节数据。即&#xff0c; ldr 是得到 4 个地…

内存管理单元(MMU)与内存控制器

内存管理单元&#xff08;Memory Management Unit &#xff09; 内存管理单元是在CPU内部 内存管理单元的作用&#xff1a; 虚拟地址到物理地址映射 存储器访问权限控制 高速缓存支持 以下出自&#xff1a;https://blog.csdn.net/yetaibing1990/article/details/88344416 如…

C++ allocator设计内存管理器

文章目录 allocator内存管理器基本属性类的设计关键功能的实现完整的内存管理器 内存管理器的测试&#xff1a;设计自定义的String类。 前情回顾&#xff1a; allocator内存管理类 allocator内存管理器 某些类需要在运行时分配可变大小的内存空间&#xff0c;一般来说我们使用…

Memory Population Guidelines for Intel 3rd Gen Xeon Scalable Processors——内存控制器

Memory Population Guidelines for Intel 3rd Gen Xeon Scalable Processors 英特尔的第三代至强可扩展处理器采用全新的内存控制器架构。本文将深入探讨这些更改&#xff0c;以及如何通过确保正确排序和填充内存模块来最大限度地提高性能。 英特尔的第三代至强可扩展处理器于 …

内存分配器 (Memory Allocator)

对于大多数开发者而言&#xff0c;系统的内存分配就是一个黑盒子&#xff0c;就是几个API的调用。有你就给我&#xff0c;没有我就想别的办法。来UC前&#xff0c;我就是这样认为的。实际深入进去时&#xff0c;才发现这个领域里也是百家争鸣&#xff0c;非常热闹。有操作系统层…

内存分配器

内存分配器&#xff08;Memory Allocator&#xff09;负责内存分配与管理。内存分配器是所有容器的基础&#xff0c;它总是隐藏在容器背后工作&#xff0c;因此内存分配器对实现者非常重要&#xff0c;而对应用者几乎可以忽略。内存分配器分为两级&#xff0c;第一级分配器直接…

小笔记——内存控制器

内存控制器 what is memory controller? 内存控制器是一个用于管理与规划从内存到CPU间传输速度的总线电路控制器。 工作方式 内存控制器控制着必要的逻辑读写DRAM&#xff0c;每隔一段时间刷新动态随机存取存储器&#xff08;DRAM&#xff09;的内容。进行读取和写入动作时&…

DDR内存控制器

DDRDouble Data Rate双倍速率同步动态随机存储器。严格的说DDR应该叫DDR SDRAM&#xff0c;人们习惯称为DDR&#xff0c;其中&#xff0c;SDRAM 是Synchronous Dynamic Random Access Memory的缩写&#xff0c;即同步动态随机存取存储器。而DDR SDRAM是Double Data Rate SDRAM的…

Linux内存控制器(二)

1. memcg_stock_pcp // 每处理器记账缓存一次从内存控制组批量申请32页, 然后把内存控制组的内存使用量加上32页 #define CHARGE_BATCH 32U // 在内存控制组记账(charge)时, 先查看当前处理器的memcg_stock_pcp // 如果memcg_stock_pcp保存的内存控制组(memcg_stock_pcp->c…

DDR控制器

SCL&#xff1a;Self-Calibration Logic&#xff0c;通过寄存器编程方式实现DDR物理层信号校准的逻辑&#xff0c;这部分逻辑全部由硬件实现&#xff0c;软件需要在物理层自动校准之前对寄存器进行初始化。 SDRAM接口宽度在保持相同速率的前提下&#xff0c;可以采用全宽、半宽…

XLINX系列之Zynq-7000系列DDR内存控制器详解

1DDR内存控制器介绍 DDR内存控制器支持DDR2&#xff0c;DDR3&#xff0c;DDR3L和LPDDR2设备&#xff0c;包括三个主要块&#xff1a;AXI存储器端口接口&#xff08;DDRI&#xff09;&#xff0c;带有交易调度器&#xff08;DDRC&#xff09;的核心控制器和具有数字PHY&#xf…

3. 内存控制器与SDRAM

内存控制器&#xff08;内存接口设备&#xff09; 地址处于不同的范围&#xff0c;会发出不同的片选引脚&#xff0c;换句话说&#xff0c;SOC外接的不同内存芯片&#xff0c;会有不同的地址范围。 CPU统一编址包括GPIO&#xff0c;各种协议类接口控制器&#xff08;UART&…

存储控制器

存储控制器是按照一定的时序规则对存储器的访问进行必要控制的设备&#xff0c;包括地址信号、数据信号以及各种命令信号的控制&#xff0c;使主设备(访问存储器的设备)能够根据自己的要求使用存储器上的存储资源。 存储控制器的作用主要就是进行接口的转换&#xff0c;将主设…

内存控制器

1.内存控制器&#xff08;Memory Controller&#xff09; 内存控制器&#xff08;Memory Controller&#xff09;是计算机系统内部控制内存并且通过内存控制器使内存与CPU之间交换数据的重要组成部分。内存控制器决定了计算机系统所能使用的最大内存容量、内存BANK数、内存类型…

Java并发包中常用类小结(一)

Java并发包中常用类小结(一) 从JDK1.5以后&#xff0c;Java为我们引入了一个并发包&#xff0c;用于解决实际开发中经常用到的并发问题&#xff0c;那我们今天就来简单看一下相关的一些常见类的使用情况。 1、ConcurrentHashMap ConcurrentHashMap其实就是线程安全版本的has…

java并发包源码分析

java并发包之AbstractQueuedSynchronizer源码分析 分析并发包首先要了解AbstractQueuedSynchronizer&#xff08;AQS&#xff09;&#xff0c;因为AQS是并发包的基础工具类。本文从ReentrantLock的公平锁出发&#xff0c;分析AbstractQueuedSynchronizer的工作过程。 lock与u…

【Java进阶】Java并发包提供了哪些并发工具类?

通过前面的学习&#xff0c;我们一起回顾了线程、锁等各种并发编程的基本元素&#xff0c;也逐步涉及了 Java 并发包中的部分内容&#xff0c;相信经过前面的热身&#xff0c;我们能够更快地理解 Java 并发包。 今天我要问你的问题是&#xff0c;Java 并发包提供了哪些并发工具…

java---JUC并发包详解

目录 前言 一、atomic包 AtomicInteger类 AtomicReference类 AtomicStampedReference类 二、locks包 接口 Condition Lock ReadWriteLock 实现类 ReentrantLock类 ReentrantReadWriteLock类 三、CountDownLatch 四、Semaphore(信号量) 总结 前言 JUC是java.u…