内存中的各区域的分配
理解操作系统中的页表和内存分配算法
理解操作系统中的页表和内存分配算法
在计算机操作系统中,页表和内存分配算法是非常重要的概念。它们负责管理计算机的内存空间,以便程序能够正常运行。本文将深入探讨这两个概念的基本原理和工作机制,并且解释它们在操作系统中的重要作用。
一、页表的基本原理和工作机制
1.页表的定义
页表是计算机操作系统中一种用来管理虚拟内存的数据结构。它将虚拟内存地址映射到物理内存地址,以便程序能够访问内存中的数据。在虚拟内存系统中,每个进程都有自己的页表,用来管理自己的虚拟地址空间。
2.页表的组成
页表由多个页表项组成,每个页表项保存了虚拟内存地址和物理内存地址之间的映射关系。通常情况下,一个页表项包括虚拟页号、
物理页框号和一些控制位,用来记录映射关系和控制页表项的访问权限。
3.页表的工作原理
当程序访问内存时,首先会生成虚拟内存地址,然后通过页表将
虚拟地址映射到物理地址。如果物理地址不在内存中,操作系统会触
发页面置换算法,将物理页面从磁盘中加载到内存中,并更新页表项
的映射关系。这样,程序就可以访问内存中的数据了。
4.页表的优化
为了提高内存访问的效率,操作系统通常会采用多级页表结构或
倒排页表等技术,来减少页表项的数量,提高页表的访问速度。
二、内存分配算法的基本原理和工作机制
1.内存分配算法的定义
内存分配算法是计算机操作系统中用来管理物理内存的一种策略。它决定了如何将内存分配给不同的进程,以及如何处理内存碎片问题。
2.内存分配算法的分类
常见的内存分配算法包括首次适应算法、最佳适应算法、循环首
次适应算法等。它们有各自的特点和适用场景,可以根据实际情况选
C C++语言变量声明内存分配
C/C++语言变量声明内存分配
2010-11-08 07:10:20| 分类:编程|字号订阅
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)—程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放。
2、堆区(heap)—在内存开辟另一块存储区域。一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—编译器编译时即分配内存。全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束后由系统释放
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b;// 栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //"123456/0"在常量区,p3在栈上。
static int c =0;//全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456/0放在常量区,编译器可能会将它与p3所指向的"123456"
linux操作系统中,内核的物理内存分配的基本方式
linux操作系统中,内核的物理内存分配的基本方式
摘要:
一、引言
二、Linux 内核物理内存分配的基本方式
1.直接内存分配
2.间接内存分配
3.动态内存分配
三、直接内存分配
1.内存分配方式
2.内存分配实例
四、间接内存分配
1.内存分配方式
2.内存分配实例
五、动态内存分配
1.内存分配方式
2.内存分配实例
六、总结
正文:
Linux 操作系统中,内核的物理内存分配的基本方式有三种:直接内存分配、间接内存分配和动态内存分配。
一、直接内存分配
直接内存分配是指内核直接从物理内存中分配一定大小的内存空间。这种
方式适用于较小的内存需求。在直接内存分配中,内核通过硬件的DMA (Direct Memory Access,直接内存访问)机制,直接将物理内存分配给需要内存的设备或模块。这种分配方式的优点是速度快,因为避免了额外的复制和同步操作。
实例:在Linux 内核中,字符设备驱动程序常常使用直接内存分配方式来分配内存。例如,一个字符设备驱动程序需要1024 字节的内存空间,它可以使用如下代码进行直接内存分配:
```c
#include <linux/slab.h>
#include <linux/fs.h>
struct my_device {
// 设备私有数据
};
static int my_device_open(struct inode *inodep, struct file *filep)
{
// 分配内存
struct my_device *my_dev = kzalloc(sizeof(struct my_device), GFP_KERNEL);
电脑硬盘分区如何合理分配存储空间
电脑硬盘分区如何合理分配存储空间随着科技的不断进步和计算机的普及,电脑已经成为了人们生活和
工作中不可或缺的工具。而对于电脑硬盘的管理,硬盘分区是一项非
常重要的技术。合理分配硬盘的存储空间,不仅可以提高电脑的运行
效率,还能更好地保护数据的安全。本文将介绍如何根据不同需求和
使用习惯,合理地分配电脑硬盘的存储空间。
一、硬盘分区的必要性
在讨论如何合理分配存储空间之前,我们首先要明确硬盘分区的必
要性。硬盘分区是将一个物理硬盘分割成多个逻辑驱动器的过程。通
过硬盘分区,我们可以将不同类型的文件和数据存储到不同的分区中,实现更有效和有序的数据管理。
其次,硬盘分区还能提高电脑性能和数据安全。例如,我们可以将
操作系统和程序文件存储在一个分区中,将个人文件和媒体文件存储
在另一个分区中。当系统崩溃或需要重装系统时,只需要格式化或恢
复系统分区,而不会丢失个人文件。
二、逻辑分区和扩展分区
在开始分区之前,我们需要先了解逻辑分区和扩展分区的概念。逻
辑分区是在主分区或扩展分区内创建的分区,用于存储数据,而扩展
分区是逻辑分区的容器,可以容纳多个逻辑分区。
根据硬盘的分区方案,我们可以将硬盘分为主分区和扩展分区。主分区可以用来安装操作系统和常用软件,而扩展分区可以用来存储个人文件和其他辅助软件。
三、操作系统和程序分区
对于日常使用电脑的用户来说,将操作系统和程序分区是一种常见的做法。将操作系统和常用程序安装在一个分区中,可以提高系统的运行速度和响应能力。这个分区通常被称为C盘,应该分配较大的存储空间,例如100GB以上,以确保操作系统和程序能够正常运行。除此之外,我们还需要保证该分区有足够的空间用于更新和升级操作系统和程序。
c语言中内存分配的几种方式
c语言中内存分配的几种方式
1.静态内存分配:在程序编译时就已经分配好了一块固定大小的内存空间,程序运行时一直存在。例如:全局变量和静态变量。
2. 栈式内存分配:在函数调用时,在栈上分配一块固定大小的内存空间,函数执行完毕后,内存自动释放。例如:局部变量。
3. 堆式内存分配:程序在运行时动态地分配内存空间,可以根据需要分配和释放内存,由程序员控制。例如:动态分配内存的函数malloc()和free()。
4. 内存映射文件:将文件映射到内存中,使得可以像访问内存一样读取文件中的数据。例如:mmap()函数。
5. 共享内存:多个进程可以共享同一块内存空间,使得进程间通信更加高效。例如:shmget()和shmat()函数。
6. 内存池:由程序员预先分配一块内存,然后使用内存池进行动态分配和释放内存,可以减小内存碎片化的问题。例如:内存池库jemalloc。
注意:在程序中合理使用内存分配方式是提高程序效率和性能的重要一步。
- 1 -
堆内存分配策略
堆内存分配策略
堆内存分配策略
1. 什么是堆内存分配策略?
堆内存分配策略是指在程序运行过程中,操作系统如何为程序分
配和管理堆内存的一种规则和方式。堆内存分配策略直接影响程序的
性能和内存的利用效率。
2. 常见的堆内存分配策略
以下是一些常见的堆内存分配策略:
•首次适应算法:按照从低地址到高地址的顺序查找可用内存块,找到满足要求的第一个内存块进行分配。这种策略简
单且容易实现,但可能导致内存碎片化问题。
•最佳适应算法:按照从小到大的顺序查找可用内存块,选择最小且能满足要求的内存块进行分配。这种策略尽量减小内
存碎片化问题,但分配时间较长。
•最坏适应算法:按照从大到小的顺序查找可用内存块,选择最大的内存块进行分配。这种策略能够获得最大的可用内存
块,但同样会导致内存碎片化问题。
•循环首次适应算法:在首次适应算法的基础上进行改进,从上一次分配位置开始查找可用内存块,降低了查找的成本。
•伙伴系统算法:将可用内存块按照2的幂次进行划分,每个块的大小是前一个块的两倍。分配内存时,根据需求大小选
择合适的块进行分配。这种策略避免了内存碎片化问题,并且分
配时间较短,但需要额外的管理开销。
3. 如何选择合适的堆内存分配策略?
选择合适的堆内存分配策略需要根据具体的应用场景和要求进行
综合考虑。以下几个因素值得关注:
•内存碎片化问题:如果应用程序需要频繁进行内存分配和释放,且对内存利用效率要求较高,可以选择能够减少内存
碎片化问题的策略,如最佳适应算法或伙伴系统算法。
•分配时间:如果应用程序对内存分配的速度要求较高,可以选择分配时间较短的策略,如首次适应算法或伙伴系统算法。
描述内存分配方式以及它们的区别
描述内存分配方式以及它们的区别
1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。
1
C++内存分配的五种方法
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多,在《const的思考》一文中,我给出了6种方法)
明确区分堆与栈
在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。
首先,我们举一个例子:
void f() { int* p=new int[5]; }
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用o perator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:
分区存储管理实验报告
分区存储管理实验报告
分区存储管理实验报告
一、引言
分区存储管理是计算机操作系统中的重要概念之一,它的目的是将计算机的内存划分为若干个不同的区域,以便更有效地管理和利用内存资源。本实验旨在通过实际操作,深入理解分区存储管理的原理和实现方式。
二、实验目的
1. 掌握分区存储管理的基本原理;
2. 熟悉分区存储管理的实现方式;
3. 了解分区存储管理的优缺点。
三、实验方法
本实验采用了虚拟机技术,在虚拟机上搭建了一个简单的操作系统环境。通过操作系统提供的命令和工具,对内存进行分区存储管理的相关操作和观察。
四、实验过程
1. 创建分区
在操作系统中,我们可以使用命令或工具来创建分区。通过指定分区的大小和位置,将内存划分为不同的区域。这些区域可以用来存储不同的程序和数据。
2. 分配内存
一旦分区创建完成,我们可以使用操作系统提供的命令或API来分配内存。分配内存时,需要指定所需内存的大小和分区的位置。操作系统会检查分区的空闲情况,并将所需内存分配给请求的进程。
3. 回收内存
当进程不再使用分配给它的内存时,操作系统可以回收这部分内存,并将其标
记为空闲状态。这样,其他进程可以再次申请并使用这部分内存。
4. 碎片整理
在长时间运行的系统中,由于内存的分配和回收,可能会产生内存碎片。内存
碎片是指内存中存在的一些不连续且无法利用的小块空闲内存。为了更有效地
利用内存资源,操作系统可以定期进行碎片整理,将相邻的小块空闲内存合并
成较大的连续空闲内存。
五、实验结果
通过实验,我们成功地创建了多个分区,并成功地分配了内存给不同的进程。
linux物理内存分配方式
linux物理内存分配方式
linux物理内存分配方式:
1、直接映射:每个页面直接映射到内核的线性地址空间中,页面的大小是固定的,通常是4KB。
2、多级页表映射:在x86架构中,使用多级页表映射方式,将虚拟地址逐级映射到物理地址。
3、段式映射:在保护模式下,内存被划分为多个段,每个段的大小和属性可以不同。每个段有一个段描述符,描述该段的基址、长度、权限等信息。
4、页式映射:在页式映射中,将内存划分为固定大小的页面,每个页面大小通常为4KB。每个页面都有一个页表项,用于映射虚拟地址到物理地址。
这些分配方式都是在内核态进行管理的,由操作系统负责分配和管理物理内存资源。
C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)
C语⾔中内存分布及程序运⾏中(BSS段、数据段、代码段、堆
栈)
BSS段:(bss segment)通常是指⽤来存放程序中未初始化的全局变量的⼀块内存区域。BSS是英⽂Block Started by Symbol的简称。BSS 段属于静态内存分配。
数据段:数据段(data segment)通常是指⽤来存放程序中已初始化的全局变量的⼀块内存区域。数据段属于静态内存分配。
代码段:代码段(code segment/text segment)通常是指⽤来存放程序执⾏代码的⼀块内存区域。这部分区域的⼤⼩在程序运⾏前就已经确定,并且内存区域通常属于只读 , 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含⼀些只读的常数变量,例如字符串常量等。程序段为程序代码在内存中的映射.⼀个程序可以在内存中多有个副本.
堆(heap):堆是⽤于存放进程运⾏中被动态分配的内存段,它的⼤⼩并不固定,可动态扩张或缩减。当进程调⽤malloc/free等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)/释放的内存从堆中被剔除(堆被缩减)
栈(stack) :栈⼜称堆栈,存放程序的局部变量(但不包括static声明的变量, static 意味着在数据段中存放变量)。除此以外,在函数被调⽤时,栈⽤来传递参数和返回值。由于栈的先进先出特点,所以栈特别⽅便⽤来保存/恢复调⽤现场。储动态内存分配,需要程序员⼿⼯分配,⼿⼯释放
下图是APUE中的⼀个典型C内存空间分布图
例如:
#include <stdio.h>
磁盘分配的三种方法
磁盘分配的三种方法
磁盘分配是指将计算机系统中的磁盘空间划分为若干个逻辑部分,并为每个部分分配相应的存储空间的过程。磁盘分配的方法有很多种,其中比较常用的有连续分配、链接分配和索引分配三种方法。
一、连续分配
连续分配是最简单、最直观的一种磁盘分配方法。它的原理是将磁盘空间划分为一系列连续的区域,每个区域称为一个分区。在连续分配中,每个文件或目录占用一个或多个连续的磁盘分区。当需要为文件或目录分配存储空间时,系统会为其分配一个连续的磁盘分区,当该文件或目录的大小超过已分配的磁盘分区时,系统会为其分配下一个连续的磁盘分区。
连续分配的优点是简单易实现,读写速度较快。然而,它也存在一些问题。首先,连续分配会造成外部碎片,即已分配的磁盘分区之间的空闲空间无法被有效利用。其次,如果需要存储的文件或目录大小超过了连续的磁盘分区大小,就无法进行连续分配,导致无法存储。
二、链接分配
链接分配是一种将文件或目录分散存储在磁盘上的分配方法。在链接分配中,每个文件或目录占用的存储空间可以是任意的、不连续的磁盘分区。为了实现链接分配,系统需要为每个文件或目录维护
一个链接表,记录其存储空间的分散情况。
链接分配的优点是可以充分利用磁盘空间,避免了外部碎片的问题。然而,链接分配也存在一些问题。首先,由于文件或目录存储空间的分散,读取文件或目录时需要进行多次磁盘寻道,读写速度较慢。其次,链接分配需要额外的链接表来记录存储空间的分散情况,增加了系统的开销。
三、索引分配
索引分配是一种使用索引表来记录文件或目录存储空间分配情况的方法。在索引分配中,系统为每个文件或目录维护一个索引表,记录其存储空间的分配情况。索引表中的每一项对应一个存储块,记录了该存储块的地址。
.prm详解
.prm详解
⼀、内存分配
1.资源分布
如上图所⽰,单⽚机型号最后的数字也就代表了单⽚机中Flash的⼤⼩,S12G128 表⽰Flash有128K Byte,S12G192 表⽰Flash有192K Byte。但是S12(X)所使⽤的内核CPU12(X)的地址总线为16位,寻址范围最⼤为2^16 =64K Byte,⽽这64K Byte的寻址空间还包括寄存器、EEPROM(利⽤Data Flash模拟)、RAM等,因此不是所有的64K Byte都是⽤来寻址FLASH。所以在S12(X)系列单⽚机中,很多资源是以分页的形式出现的,其中包括EEPROM、RAM、FLASH。EEPROM的每页⼤⼩为1K Byte,RAM的每页⼤⼩为4K Byte,FLASH的每页⼤⼩为16K Byte。因此G128中EEPROM的页数为4K/1K = 4页,RAM的页数为8K/4K = 2页,Flash的页数为128K/16K = 8页。
2.本地内存地址和全局内存地址之间的关系
在单⽚普通模式中,复位后,所有内存资源的映射如图⼆所⽰,其中从0x0000-0x03FF的1K范围内映射为寄存器区,如I/O端⼝寄存器等,当然寄存器没有那么多,后⾯的⼀部分其实没有使⽤;
从0x0400-0x3FFF存放着EEPROM、Flash Space、RAM,具体可到该模块去看细化的分配。
从0x4000-0xFFFF的总共48K的空间为Flash区,分为三页。其中第⼀页和第三页为固定的Flash页(⾮分页),中间的⼀页(0x8000-
C语言的内存分配详解
下面是关于new 操作的说明
1、new运算符返回的是一个指向所分配类型变量 new运算符返回的是一个指向所分配类型变量 (对象)的指针。对所创建的变量或对象,都是 对象)的指针。对所创建的变量或对象, 通过该指针来间接操作的, 通过该指针来间接操作的,而动态创建的对象本 身没有名字。 身没有名字。 一般定义变量和对象时要用标识符命名, 2、一般定义变量和对象时要用标识符命名,称命 名对象,而动态的称无名对象( 名对象,而动态的称无名对象(请注意与栈区中的 临时对象的区别,两者完全不同:生命期不同, 临时对象的区别,两者完全不同:生命期不同, 操作方法不同,临时变量对程序员是透明的) 操作方法不同,临时变量对程序员是透明的)。 堆区是不会在分配时做自动初始化的( 3、堆区是不会在分配时做自动初始化的(包括清 ),所以必须用初始化式(initializer)来显 所以必须用初始化式(initializer) 零),所以必须用初始化式(initializer)来显 式初始化。new表达式的操作序列如下 表达式的操作序列如下: 式初始化。new表达式的操作序列如下:从堆区分 配对象,然后用括号中的值初始化该对象。 配对象,然后用括号中的值初始化该对象。
在堆中建立动态一维数组
1、申请数组空间: 申请数组空间: 指针变量名=new 类型名[下标表达式] 指针变量名=new 类型名[下标表达式]; 注意: 下标表达式”不是常量表达式, 注意:“下标表达式”不是常量表达式,即它的值不 必在编译时确定,可以在运行时确定。 必在编译时确定,可以在运行时确定。 释放数组空间: 2、释放数组空间: delete [ ]指向该数组的指针变量名; 指向该数组的指针变量名; 注意:方括号非常重要的 如果delete语句中少了方 非常重要的, 注意:方括号非常重要的,如果 语句中少了方 括号,因编译器认为该指针是指向数组第一个元素的, 括号,因编译器认为该指针是指向数组第一个元素的, 会产生回收不彻底的问题( 会产生回收不彻底的问题(只回收了第一个元素所占 空间),加了方括号后就转化为指向数组的指针, ),加了方括号后就转化为指向数组的指针 空间),加了方括号后就转化为指向数组的指针,回 收整个数组。 的方括号中不需要填数组元素 收整个数组。delete [ ]的方括号中不需要填数组元素 的方括号中 系统自知。即使写了,编译器也忽略。 数,系统自知。即使写了,编译器也忽略。
kvm 内存分配机制
kvm 内存分配机制
(原创实用版)
目录
1.KVM 内存分配机制简介
2.KVM 内存分配策略
3.KVM 内存分配的具体方式
4.KVM 内存分配的优化方法
正文
【KVM 内存分配机制简介】
KVM,即 Kernel-based Virtual Machine,是基于内核的虚拟机,是Linux 内核中的一个功能模块,它使 Linux 系统具有虚拟化功能。在 KVM 中,内存分配是一个重要的环节。合理的内存分配可以提高虚拟机的性能,而不合理的内存分配则可能导致虚拟机性能下降。因此,了解 KVM 的内存分配机制对于优化 KVM 的性能具有重要意义。
【KVM 内存分配策略】
KVM 内存分配策略主要包括以下几种:
1.静态内存分配:静态内存分配是指在虚拟机启动时,KVM 将为虚拟机分配固定大小的内存,直到虚拟机关闭,这部分内存都不会被回收。静态内存分配的优点是内存分配过程简单,缺点是不能根据虚拟机的实际需求动态调整内存大小。
2.动态内存分配:动态内存分配是指 KVM 根据虚拟机的实际需求动态分配内存。当虚拟机需要更多内存时,KVM 会分配更多的内存;当虚拟机不再需要某些内存时,KVM 会将这部分内存回收。动态内存分配的优点是能够根据虚拟机的实际需求动态调整内存大小,缺点是内存分配过程较为复杂。
3.内存复用:内存复用是指 KVM 将虚拟机释放的内存回收后,将其分配给其他虚拟机使用。内存复用可以提高内存的利用率,从而提高虚拟机的性能。
【KVM 内存分配的具体方式】
KVM 内存分配的具体方式主要包括以下几种:
c语言程序中内存的划分及各个段的含义
c语言程序中内存的划分及各个段的含义
【C语言程序中内存的划分及各个段的含义】
1. 引言
C语言是一种广泛应用在系统编程和嵌入式开发中的高级编程语言,其灵活性和效率使得它成为了众多开发者的首选。在C语言程序中,内存的划分及各个段的含义是一个至关重要的话题。本文将从简单到复杂,由浅入深地探讨这一主题。
2. 内存的基本划分
在C语言程序中,内存主要被划分为四个部分:
- 代码段:也称为文本段,用来存储程序的代码。
- 数据段:用来存储全局变量和静态变量。
- 栈:用来存储局部变量和函数的参数。
- 堆:用来动态分配内存。
3. 代码段
代码段是存储程序执行代码的地方。在程序执行之前,代码段被加载到内存中,并且通常是只读的,以防止程序意外修改其内容。在代码段中,指令被存储为机器可执行的二进制代码,并且按照程序的控制流顺序执行。
4. 数据段
数据段用来存储全局变量和静态变量。全局变量是在函数外部定义的变量,它在程序的整个执行过程中都是可见的。而静态变量则是在函数内部使用关键字static声明的变量,它的生命周期与程序的执行时间相同,但是只能在定义它的函数中可见。
5. 栈
栈用来存储局部变量和函数的参数。每当一个函数被调用时,栈上就会分配一段内存空间,用来存储该函数的参数和局部变量。当函数执行完毕后,该段内存空间就会被释放,以便其他函数使用。
6. 堆
堆是用来动态分配内存的地方。在程序执行过程中,有时需要动态地分配内存空间,以存储一些临时数据或者动态创建一些对象。C语言提供了一些标准的库函数,如malloc和free,用来在堆上进行内存的分配和释放。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
程序中用来存放数据的内存分为四块,其实另有一块用于存放代码,这里我们不讨论,这四块分别是:
1、全局区(静态区)(static):全局变量和静态变量都存储在这块区域,与其他变量的明显区别就是生命周期不同,在程序结束时,系统会释放这块资源
2、文字常量区:常量字符串就是放在这块区域,即是我们常说起的常量池。这块也是在程序结束时由系统释放。
3、栈区(stack):存放函数的参数值,局部变量的值等。这块的数据大家就很熟悉了,在进入作用域时分配占用内存,离开作用域时释放占用内存
4、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由系统回收。由于这个原因,在C和C++中就有能产生大量程序员分配但忘记释放的堆区内存,造成可使用内存越来越少,这个被称之为内存泄露。而在java中,因为有了垃圾收集机制,这样的内存会被自动处理掉,所以在java中,反倒不需要程序员去释放内存了。
那么栈和堆的区别到底在哪里呢?
1、内存分配方面:
堆:一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式是类似于链表。可能用到的关键字如下:new、malloc、delete、free等等。
栈:由编译器(Compiler)自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、申请方式方面:
堆:需要程序员自己申请,并指明大小。在c中malloc函数如p1 = (char *)malloc(10);在C++,java中用new运算符,但是注意p1、p2本身是在栈中的。因为他们还是可以认为是局部变量。
栈:由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b 开辟空间。
3、系统响应方面:
堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
4、大小限制方面:
堆:是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
栈:在Windows下, 栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是固定的(是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
5、效率方面:
堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方
便,另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。
栈:由系统自动分配,速度较快。但程序员是无法控制的。
6、存放内容方面:
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
栈:在函数调用时第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈,然后是函数中的局部变量。注意: 静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
这么多看起来是不是很痛苦??不急,先记住栈和堆区别的第一点和第二点,这个是基础哦。其实有个小诀窍:
数据类型变量名;这样定义的东西在栈区。
new 数据类型();或者malloc(长度); 这样定义的没有名字的东西就在堆区哦。