【C语言】内存管理

news2024/12/22 22:33:52

C语言-内存管理

    • 一、C进程内存布局
    • 二、栈内存
      • 1、存储在栈内存中的参数有哪些?
      • 2、栈内存的特点?
    • 三、静态数据
    • 四、数据段与代码段
    • 五、堆内存

一、C进程内存布局

\qquad 任何一个程序,正常运行都需要内存资源,用来存放诸如变量、常量、函数代码等等。这些不同的内容,所存储的内存区域是不同的,且不同的区域有不同的特性。因此我们需要研究其内存布局,逐个了解不同内存区域的特性。
\qquad 每个C语言进程都拥有一片结构相同的虚拟内存,所谓的虚拟内存,就是从实际物理内存映射出来的地址规范范围,最重要的特征是所有的虚拟内存布局都是相同的,极大地方便内核管理不同的进程。例如三个完全不相干的进程p1、p2、p3,它们很显然会占据不同区段的物理内存,但经过系统的变换和映射,它们的虚拟内存的布局是完全一样的。

  • PM:Physical Memory,物理内存。
  • VM:Virtual Memory,虚拟内存。

在这里插入图片描述
将其中一个C语言进程的虚拟内存放大来看,会发现其内部包下区域:

  • 栈(stack)
  • 堆(heap)
  • 数据段
  • 代码段

在这里插入图片描述
虚拟内存中,内核区段对于应用程序而言是禁闭的,它们用于存放操作系统的关键性代码,另外由于 Linux 系统的历史性原因,在虚拟内存的最底端 0x0 ~ 0x08048000 之间也有一段禁闭的区段,该区段也是不可访问的。

虚拟内存中各个区段的详细内容:
在这里插入图片描述

二、栈内存

1、存储在栈内存中的参数有哪些?

环境变量
// 比如:声明,用到linux系统(动静态库文件)

  • 命令行参数
// argc:命令行参数个数
// argv: 命令行参数变量名
int main(int argc, char const *argv[])
{
}
  • 局部变量(包括形参)
void func(int a, int *p) // 在函数 func 的栈内存中分配
{
    double f1, f2;        // 在函数 func 的栈内存中分配
    ...                   // 退出函数 func 时,系统的栈向上缩减,释放内存
}

int main(void)
{
    int m  = 100;        // 在函数 main 的栈内存中分配
    func(m, &m);         // 调用func时,系统的栈内存向下增长
}

2、栈内存的特点?

  • 空间有限,尤其在嵌入式环境下。因此不可以用来存储尺寸太大的变量。
  • 每当一个函数被调用,栈就会向下增长一段,用以存储该函数的局部变量。
  • 每当一个函数退出,栈就会向上缩减一段,将该函数的局部变量所占内存归还给系统。
  • 注意:
    栈内存的分配和释放,都是由系统规定的,我们无法干预。
    在这里插入图片描述

三、静态数据

C语言中,静态数据有两种:

  • 全局变量:定义在函数外部的变量。
  • 静态局部变量:定义在函数内部,且被static修饰的变量。
  • 示例:
int a; // 全局变量,退出整个程序之前不会释放
void f(void)
{
    static int b; // 静态局部变量,退出整个程序之前不会释放
    printf("%d\n", b);
    b++;
}

int main(void)
{
    f();
    f(); // 重复调用函数 f(),会使静态局部变量 b 的值不断增大
}
  • 为什么需要静态数据?
    1.全局变量在默认的情况下,对所有文件可见,为某些需要在各个不同文件和函数间访问的数据提供操作上的方便。
    2.当我们希望一个函数退出后依然能保留局部变量的值,以便于下次调用时还能用时,静态局部变量可帮助实现这样的功能。
  • 注意1:
    • 若定义时未初始化,则系统会将所有的静态数据自动初始化为0
    • 静态数据初始化语句,只会执行一遍。
    • 静态数据从程序开始运行时便已存在,直到程序退出时才释放。(注意:所以不能够用太多的静态数据)
  • 注意2:
    • static修饰局部变量:使之由栈内存临时数据,变成了静态数据。
    • static修饰全局变量:使之由各文件可见的静态数据,变成了本文件可见的静态数据。
    • static修饰函数:使之由各文件可见的函数,变成了只有本文件可见的静态函数。

四、数据段与代码段

数据段细分成如下几个区域:

  • .bss (Block Started bySymbol)段:
    存放未初始化的静态数据,它们将被系统自动初始化为0
  • .data段:存放已初始化的静态数据
  • .rodata段:存放常量数据
  • 代码段细分成如下几个区域:
  • .text段:存放用户代码
  • .init段:存放系统初始化代码
    执行main函数之前,栈和堆的初始化信息会被先执行
    在这里插入图片描述
#include <stdio.h>

int num1;        // 数据段(bss):全局变量(未初始化,系统自动初始化为0)
int num2 = 100;   // 数据段(data):全局变量(已初始化)

int main(void)
{
    static int num3;        // 数据段(bss): 静态局部变量(未初始化,系统自动初始化为0)
    static int num4 = 200;   // 数据段(data):静态局部变量(已初始化)
    
    char *buf1 = "abc";    // 数据段(rodata段):字符串常量
    
    // 以上代码中的常量100、200、字符串放置在rodata 中
}
  • 注意:数据段和代码段内存的分配和释放,都是由系统规定的,我们无法干预。

五、堆内存

\qquad 堆内存(heap)又被称为动态内存、自由内存,简称堆。堆是唯一可被开发者自定义的区段,开发者可以根据需要申请内存的大小、决定使用的时间长短等。但又由于这是一块系统“飞地”,所有的细节均由开发者自己把握,系统不对此做任何干预,给予开发者绝对的“自由”,但也正因如此,对开发者的内存管理提出了很高的要求。对堆内存的合理使用,几乎是软件开发中的一个永恒的话题。

  • 堆内存基本特征:
    • 相比栈内存,堆的总大小仅受限于物理内存,在物理内存允许的范围内,系统对堆内存的申请不做限制。
    • 相比栈内存,堆内存从下往上增长。
    • 堆内存是匿名的,只能由指针来访问。
    • 自定义分配的堆内存,除非开发者主动释放,否则永不释放,直到程序退出。

在这里插入图片描述

  • 相关API:
    • 申请堆内存:malloc() / calloc()
    • 清零堆内存:bzero()
    • 释放堆内存:free()
      在这里插入图片描述
int *p = malloc(sizeof(int)); // 申请1块大小为 sizeof(int) 的堆内存
bzero(p, sizeof(int));        // 将刚申请的堆内存清零

*p = 100; // 将整型数据 100 放入堆内存中
free(p);  // 释放堆内存

// 申请3块连续的大小为 sizeof(double) 的堆内存
double *k = calloc(3, sizeof(double));

k[0] = 0.618;
k[1] = 2.718;
k[2] = 3.142;
free(k);  // 释放堆内存
  • 注意:
    • malloc()申请的堆内存,默认情况下是随机值,一般需要用 bzero() 来清零。
    • calloc()申请的堆内存,默认情况下是已经清零了的,不需要再清零。
    • free()只能释放堆内存,并且只能释放整块堆内存,不能释放别的区段的内存或者释放一部分堆内存。
  • 释放堆内存的含义:
    • 释放堆内存意味着将堆内存的使用权归还给系统。
    • 释放堆内存并不会改变指针的指向。
    • 释放堆内存并不会对堆内存做任何修改,更不会将内存清零。

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

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

相关文章

第九届“创客中国”武汉区域赛正式启幕 灵途科技勇夺前三,晋级决赛!

8月8日&#xff0c;第九届“创客中国”武汉区域赛正式启幕&#xff0c;首场聚焦先进制造领域。灵途科技勇夺先进制造领域专场企业组前三名&#xff0c;成功晋级决赛。 “创客中国”大赛是工业和信息化部组织开展的双创赛事活动&#xff0c;以构建产业链协同发展为出发点&#…

Win10 VisualStudio 2022编译ollvm 13.x

VisualStudio配置 1&#xff0c;正常配置C桌面环境 2&#xff0c;在单个组件中选择用于Windows得C Cmake工具 下载OLLVM13.x https://github.com/heroims/obfuscator/tree/llvm-13.x 解压后进入文件夹&#xff0c;命令行输入 cmake -G “Visual Studio 17 2022” -DLLVM_EN…

Java面试--设计模式

设计模式 目录 设计模式1.单例模式&#xff1f;2.代理模式&#xff1f;3.策略模式&#xff1f;4.工厂模式&#xff1f; 1.单例模式&#xff1f; 单例模式是Java的一种设计思想&#xff0c;用此模式下&#xff0c;某个对象在jvm只允许有一个实例&#xff0c;防止这个对象多次引…

依赖倒置原则:构建灵活软件架构的基石 - 通过代码实例深入解析

1.引言 1.1为什么要学习依赖倒置原则 在软件开发过程中&#xff0c;我们经常需要对代码进行修改和扩展。如果代码之间的耦合度过高&#xff0c;那么在进行修改或扩展时&#xff0c;可能会对其他部分的代码产生影响&#xff0c;甚至引发错误。这就要求我们在编写代码时&#xf…

【VS Code】 vue项目使用scss显示语法错误、build编译正常

开发vue项目&#xff0c;使用scss老是报这个错误 解决方式&#xff1a; 1.安装vetur 2.在vs code的设置中添加 "files.associations": { "*.vue": "vue" }解决&#xff1a;

线性规划约束一个矩形在Polygon内部

最近在用线性规划&#xff0c;有一个比较有趣的问题&#xff0c;记录一下思路。 如何用线性规划约束一个矩形在Polygon内部&#xff1f; 问题&#xff1a;有如下图蓝色矩形&#xff0c;用线性规划表示出绿色矩形被约束在polygon内部&#xff0c;矩形的中心坐标是(x, y),宽和高…

计算机组成原理---关于乘法电路与除法运算电路的理解

目录 一.乘法电路 1.无符号数乘法运算的硬件实现逻辑&#xff1a; 2.补码1位乘法运算的硬件实现逻辑&#xff1a; 3.无符号阵列乘法器 4.补码阵列乘法器 二.除法电路 1.原码除法运算 2.补码除法运算&#xff08;不恢复余数法&#xff09; 本篇是看湖科大与王道视频总结…

35_WebShell管理工具、中国蚁剑AntSword的安装及使用、御剑的使用、后台目录扫描

WebShell管理工具 WebShell 以asp、php、jsp或cgi等网页形式存在的一种代码执行环境主要用于网站和服务器管理由于其便利性和功能强大&#xff0c;被特别修改后的WebShell也被部分人当作网站后门工具使用国内常用的WebShell有海阳ASP木马&#xff0c;Phpspy&#xff0c;c99sh…

<Qt> 系统 - 事件

目录 前言&#xff1a; 一、事件介绍 二、事件的处理 &#xff08;一&#xff09;鼠标事件 1. 进入和离开事件 2. 鼠标点击事件 3. 释放事件 4. 双击事件 5. 移动事件 6. 滚轮事件 &#xff08;二&#xff09;键盘按键事件 1. 单个按键 2. 组合按键 &#xff08;…

如何判断监控设备是否支持语音对讲

目录 一、大华摄像机 二、海康摄像机 三、宇视摄像机 一、大华摄像机 注意&#xff1a;大华摄像机支持跨网语音对讲&#xff0c;即设备和服务器可以不在同一网络内&#xff0c;大华设备的语音通道填写&#xff1a;34020000001370000001 配置接入示例&#xff1a; 音频输入…

十日Python项目——第七日(商品购物车)

#前言&#xff1a; 在最近十天我会用Python做一个购物类电商项目&#xff0c;会用到DjangoMysqlRedisVue等。 今天是第六天&#xff0c;主要负责撰写编写关于商品购物车的编写&#xff0c;以及相应的增删改查。若是有不懂大家可以先阅读我的前六篇博客以能够顺承。 若是大家…

Github Copilot 使用技巧

&#x1f3af;目标读者 本文不包含如何安装 Github Copilot本文介绍了 Github Copilot 使用方法和一些技巧 本人已经使用 Github Copilot 2 年了&#xff0c;交了 3 次年费&#xff0c;每年 100$ 着实心痛&#xff0c;但是用着确实爽歪歪 但是感觉一直只用了一小部分功能&am…

(第二十七天)

上午 核心&#xff1a;内核中的 ipvs &#xff0c; ipvsadm 1 、安装 ipvsadm [rootnat ~] # yum -y install ipvsadm 2 、配置规则 查看所有的规则&#xff0c;如果已经配置好规则&#xff0c;重启之后也就没有了 [rootnat ~] # ipvsadm -L -n 1 、配置 vip 网卡 &…

服装租赁押金管理-押金原路退回系统开通方法

一、婚纱影楼服装租赁收押金必要性 1. 保障服装的按时归还&#xff1a; - 押金的存在能促使租客按时归还服装&#xff0c;避免因拖延归还影响后续的租赁业务。比如&#xff0c;在一些大型活动期间&#xff0c;服装租赁需求旺盛&#xff0c;如果租客不按时归还&#xff0c;…

HTML样式- CSS——WEB开发系列08

一、HTML 基础概述 HTML 用于创建网页的结构。网页的所有内容&#xff0c;例如文本、图像、链接、表单等&#xff0c;都是通过 HTML 标签来定义的。以下是一个简单的 HTML 文档结构示例&#xff1a; <!DOCTYPE html> <html lang"en"> <head><…

matlab 音频音量处理(音量大小按照dB调节)

1 音量(声压级)以分贝(dB)表示的计算公式为: 2 % 已知的 x 值 x = 0:-1:-127; % 在这里填入 x 的具体值% 计算 y %y = 10

浅谈php://filter的妙用

文章目录 分析源码巧用编码与解码利用字符串操作方法 分析源码 <?php $content <?php exit; ?>; $content . $_POST[txt]; file_put_contents($_POST[filename], $content);首先&#xff0c;先分析一下这段代码。 首先他定义了content为’<?php exit;?>‘…

计算机网络17——IM聊天系统——客户端核心处理类框架搭建

目的 拆开客户端和服务端&#xff0c;使用Qt实现客户端&#xff0c;VS实现服务端 Qt创建项目 Qt文件类型 .pro文件&#xff1a;配置文件&#xff0c;决定了哪些文件参与编译&#xff0c;怎样参与编译 .h .cpp .ui&#xff1a;画图文件 Qt编码方式 Qt使用utf-8作为编码方…

服务器被ddos攻击多久能恢复?具体怎么操作

服务器被ddos攻击多久能恢复&#xff1f;如果防御措施得当&#xff0c;可能几分钟至几小时内就能缓解&#xff1b;若未采取预防措施或攻击特别猛烈&#xff0c;则可能需要几小时甚至几天才能完全恢复。服务器被DDoS攻击的恢复时间取决于攻击的规模和强度、服务器的配置和性能以…

【C++】类与对象(中)_7.const成员函数

7.const成员 7.1 const修饰类的成员函数 将const修饰的类成员函数称之为const成员函数&#xff0c;const修饰类成员函数&#xff0c;实际修饰该成员函数隐含的this指针&#xff0c;表明在该成员函数中不能对类的任何成员进行修改。 我们来看看下面的代码 #define _CRT_SECU…