内存的分区

一、分区

内存一般分为四个区可以使用,存放不同的数据,使用方式也不同,分别是:堆、栈、全局(静态)、代码区。

对于一个程序来说,编译程序需要占用的是五个部分:堆、栈、全局(静态)、文字常量、代码区

二、区的功能

  1. 代码区:存放编译后的可执行二进制代码,机器指令,该区在运行中为只读
  2. 文字常量区:存放常量字符串,该区在编译时已经确定,所以运行中为只读
  3. 全局区(静态区):存放全局变量、static修饰的全局或局部变量以及函数,这个区通常分为两个子区:data区和bss区,运行时均可读可写
    1. data区:存放的是已经初始化的全局、静态变量(包括static修饰的全局或局部变量)。因为这些变量在程序启动时需要有明确的初始值,所以它们被存储在data区中,运行中为可读可写
    2. bss区:存放的是未初始化的全局或静态变量。这些变量在程序开始执行之前会被系统初始化为0或NULL(对于指针而言),运行中可读可写
  4. 栈区(stack):存放函数的参数值,局部变量的值,返回地址以及用于管理函数调用的其他信息,运行时可读可写
  5. 堆区(heap):用于动态内存分配的区域,通常由程序员通过malloc、calloc、realloc等函数手动管理,一般由程序员自己手动释放空间,或者由程序结束时由OS(计算机系统)释放空间,运行时可读可写
#include <stdio.h>
#include <stdlib.h>

int a = 10;//全局变量data区
int *p;//全局变量bss区

int main()
{
    int b;//栈区
    int s[] = {1, 2, 3, 4, 5};//栈区数组直接在栈区,因为它是直接将字面量值放入栈区
    char c[] = "hello world";//栈区
    int *q;//栈区
    char *r="12345";//12345\0在常量区,*r在栈区指向第一个字符
    static int d = 20;//全局data区
    p = (int*)malloc(5*sizeof(int));//堆区,这里的p指向堆区中第一个int变量的地址
    q = (int*)malloc(5*sizeof(int));//堆区
//    strcpy(p, 12345);//这个函数的对象需要是char*
//    strcpy(q, 67890);
    p[0]=12345;//p[0]在堆区,在运行时,12345是作为一个立即数存在于指令中,不是在某个特定的区域,如果是字符串,则会存储在常量区
    q[0]=67890;
    printf("%d\n", p[0]);
    printf("%d\n", q[0]);
    printf("%s\n", r);
    free(p);//注意释放空间!!!这是一个好习惯
    free(q);
    return 0;
}

三、分区的变化

运行之前

即编译完成之后,分为代码、data、bss区

代码区:存放了编译后的二进制指令,该区域为只读

data区:存放了已经初始化的全局变量、静态变量

bss区:存放未初始化的全局、静态变量,在加载到内存中时由操作系统初始化为0或NULL

为什么要将程序的指令与程序的数据分开存放?

独立的内存管理:内存的分配和回收更高效,方便

共享与保护:指令会被频繁的访问和执行,数据可能需要频繁的修改,分开放可以防止数据修改时,影响到指令的执行

地址空间隔离:分开可以防止程序之间地址冲突,可以避免一个程序的指令或数据覆盖掉另一个程序的内存

 运行后

程序运行后,分为代码、data、bss、栈、堆区

前三个编译时已确定,不可改变

栈区:存放函数的参数值、返回地址、局部变量,生命周期为函数的调用到释放

堆区:用于动态内存管理分配,空间远大于栈区,没有固定的分配顺序,生命周期是程序员的分配到主动释放或程序结束系统自动释放

四、缓冲区

Buffer是一种内存区域,这块区域用来暂存数据,以便在不同的数据流之间进行高效的数据传输,可以减少处理器和I/O设备之间的等待时间,提高系统性能

 缓冲区如何运行

假设你有一台打印机,它每次只能打印一张纸。当你有一大堆文件需要打印时,你会怎么做?

  1. 直接打印

    • 你需要一张一张地手动将文件放入打印机,每张文件打印完成后,你再放下一张。
    • 在打印过程中,你无法做其他事情,比如处理电子邮件、浏览网页或者进行计算。
    • 打印一张文件可能需要几秒钟,如果你有1000000张文件,那将需要很长时间。
  2. 使用缓冲区打印

    • 你可以将1000000张文件分成若干批,每批包含一定数量的文件。
    • 首先,你将一批文件放入打印机中,然后开始处理其他事情,比如处理电子邮件、浏览网页或者进行计算。
    • 当你准备好处理下一批文件时,你已经完成了之前的任务。
    • 当你处理完一批文件后,你可以继续处理下一批,直到所有的文件都打印完成。

通过使用缓冲区,你可以在打印机打印文件的同时,处理其他任务,这样就提高了效率,减少了等待打印完成的时间。

在计算机系统中,缓冲区的作用类似。当系统需要从硬盘读取大量数据时,它不会每次只读取一个数据块,而是先将多个数据块读取到内存中的缓冲区中。这样,系统可以在等待数据从硬盘传输到内存的同时,执行其他任务。当缓冲区中的数据处理完成后,系统再从硬盘读取更多的数据块,以此类推,直到所有数据都处理完成。

缓冲策略

缓冲区针对不同的环境有着不同的缓冲策略,而操作系统或应用程序在处理文件时使用的缓冲策略,为全缓冲、行缓冲、不带缓冲三种

  1. 全缓冲:只有当缓冲区存满时,才会一次性输入或者输出,对于块数据的写入,可以减少磁盘I/O操作的次数,提高效率,适合于大型的二进制文件等
  2. 行缓冲:每次输入输出只处理一行数据,也就是说只有遇到换行符才会进行磁盘I/O操作,适合文本文件的写入等
  3. 不带缓冲:直接从源(内存)写入到目标(磁盘)或者读,适合于数据量小,或者实时性要求很高的情况,可能会频繁的进行磁盘的I/O操作,会影响性能

缓冲区的刷新

指将缓冲区中的数据写入到目标存储设备的过程。在操作系统和应用程序中,缓冲区刷新通常是为了确保数据的一致性和可靠性。以下是什么情况下会发生该操作

  1. 缓冲区满时:当达到缓冲区容量限制时,会触发刷新,将缓冲区中数据写入到目标存储设备
  2. 系统命令:当应用程序或者系统通过命令请求刷新时,如调用flush或fsync函数
  3. 系统定时器:操作系统可能会设置定时器,定期检查是否需要刷新,如果缓冲区中的数据不再需要或者不是最新的,可能会触发自动刷新缓冲区
  4. 当系统遇到异常情况或者系统关闭时,操作系统会自动刷新缓冲区,确保所有写入的数据都已经写入到文件中

五、堆栈的区别

堆栈的区别
分配方式静态分配,固定大小的内存块,win64下栈的大小默认是2M,如果申请空间超过栈的剩余空间,将提示overflow动态分配,向高地址扩展的数据结构,操作系统用链表来存储空闲的地址,所以不是连续的,遍历方式为从低到高地址,它受限于操作系统的虚拟内存,因此比较灵活,空间较大
优缺点栈是由系统自动分配的,空间较小,但是速度较快堆是由程序员分配的,速度较慢,易产生内存碎片,但是使用方便,空间大
系统响应方式只要剩余空间大于申请空间就可以申请,否则会报错:栈溢出系统收到内存申请的请求时,会遍历链表,当寻找到第一个空间大于申请空间的堆节点,就会从链表中删除该节点,如果大于申请空间,那么把剩余的空间重新写入链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是你彬哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值