【操作系统】堆和内存分配

  光有栈对于面向对象过程的程序设计远远不够,因为栈上的数据在函数返回的时候就会被释放带哦,所以无法将数据传递至函数外部。而全局变量没有办法动态地产生,只能在编译的时候定义,有很多情况下缺乏表现力。在这种情况下,堆(Heap)是唯一的选择

  堆是一块巨大的内存空间,常常占据整个虚拟内存空间的绝大部分。在这片空间里,程序可以请求一块连续内存,并自由地使用,这块内存在程序主动放弃之前都会一直保持有效。下面是一个申请堆空间最简单的例子。

  

1 int main()
2 {
3     char * p= (char*)malloc(1000);
4     /*use p as an array of size of 1000*/
5     free(p);
6 }

在第三行用malloc申请了1000个字节的空间之后,程序可以自由地使用这1000个字节,直到程序用free函数释放它。

堆分配算法

  对于程序来说,堆空间只是程序向操作系统申请划出来的一大块地址空间。而程序在通过malloc申请内存空间的大小却是不一定的。从数个字节到数个GB都是有可能的。于是我们必须将堆空间管理起来,将它分块地按照用户需求出售给最终的程序,并且还可以按照一定的方式收回内存。其实这个问题可以归结为:如何管理一大块内存空间,能够按照需求分配、释放其中的空间,这就是堆分配算法。

  1. 空闲链表

  空闲链表(Free List)的方法实际上就是把堆中各个空闲的块按照链表的方式连接起来,当用户请求一块空间时,可以遍历整个列表,直到找到合适大小的块并且将它拆分:当用户请求一块内存空间时,可以遍历整个列表,直到找到合适大小的块并且将它拆分:当用户释放空间时将它合并到空闲链表中。

  我们首先需要一个数据结构来等级堆空间里所有需哟啊的空闲时间,这样才能知道程序请求空间的时候该分配给它哪一块内存。这样的结构有很多种,这里介绍最简单的一种——空闲链表。

  空闲链表是这样一种数据结构,在堆里的每一个空闲空间的开头(或结尾)有一个头(header),头结构里记录了上一个(prev)和下一个(next)空闲块的地址,也就是说,所有的空闲块形成了一个链表。如下图所示:

  

  首先在空闲链表里查找足够容纳请求大小的一个空闲块,然后将这个块分成两部分,一部分为请求的空间,另一部分剩余下来的空闲空间。下面将链表里对应原来空闲块的结构更新为新的剩下的空闲块,如果剩下的空闲块大小为0,则直接将这个结构从链表里删除。下图掩饰了用户请求一块喝空闲块恰好相等的内存后堆的状态

这样的空闲链表实现尽管简单,但在释放空间的时候,给定一个已分配块的指针,堆无法确定这个块的大小。一个简单的解决方法是当用户请求k个字节空间的时候,我们实际分配k+4个字节,这4个字节用于存储该分配的大小,即k+4,。这样释放该内存的时候只要看看这4个字节的值,就能知道该内存的大小,然后将其插入到空闲链表里就可以了。

  当然这仅仅是最简单的一种分配策略,这样的思路存在很多问题。例如,一旦链表被破坏,或者记录长度的那4个字节被破坏,整个堆就无法正常工作,而这些恰恰很容易被越界读写所接触到。

 

  2.位图

  使用位图方法时,内存可能被划分成小到几个字或大到几千字节的分配单元。每个分配单元对应于位图中的一位,0表示空闲,1表示占用。

  分配单元的大小是一个重要的设计因素。分配单元越小,位图越大。然而即使只有4个字节大小的分配单元,32位的内存也只需要位图中的1位;32n的内存需要n位的位图,所以位图只占用了1/33的内存。若选择比较大的分配单元,则位图更小。但若进程的大小不是分配单元的整数倍,那么在最后一个分配单元中就会有一定数量的内存被浪费了。

  因为内存的大小和分配单元的大小决定了位图的大小,所以它提供了一种简单的利用一块固定大小的内存区就能对内存使用情况进行记录的方法。这种方法的主要问题是,在决定把一个占k个分配单元的进程调入内存时,存储管理器必须搜索位图,在位图中找出k个连续的0串。查找位图中指定长度的连续0串是耗时的操作(因为在位图中该串可能跨越字的边界),这是位图的缺点。

时间: 2024-10-19 01:23:45

【操作系统】堆和内存分配的相关文章

浅析栈区和堆区内存分配的区别

以下是对栈区和堆区内存分配的区别进行了详细的分析介绍,需要的朋友可以过来参考下 一直以来总是对这个问题的认识比较朦胧,我相信很多朋友也是这样的,总是听到内存一会在栈上分配,一会又在堆上分配,那么它们之间到底是怎么的区别呢?为了说明这个问题,我们先来看一下内存内部的组织情况. 从上图可知,程序占用的内存被分了以下几部分. 1.栈区(stack)由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,类似于平时我们所说的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分

浅析栈区和堆区内存分配的区别(转)

以下是对栈区和堆区内存分配的区别进行了详细的分析介绍,需要的朋友可以过来参考下 一直以来总是对这个问题的认识比较朦胧,我相信很多朋友也是这样的,总是听到内存一会在栈上分配,一会又在堆上分配,那么它们之间到底是怎么的区别呢?为了说明这个问题,我们先来看一下内存内部的组织情况. 从上图可知,程序占用的内存被分了以下几部分. 1.栈区(stack)由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,类似于平时我们所说的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分

转!!Java虚拟机堆的内存分配和回收

Java内存分配和回收,主要就是指java堆的内存分配和回收.java堆一般分为2个大的区域,一块是新生代,一块是老年代.在新生代中又划分了3块区域,一块eden区域,两块surviver区域.一般称为from surviver和to surviver.这些区域的大小可以自己指定.比如:(-Xms20M 表示可用堆内存大小:-Xmx40M 表示最大堆内存,在堆内存大小不够时,会扩展到最大堆内存:-Xmn10M 表示新生代内存大小). 新生代中的对象会在eden区域分配,然后eden区域的内存不够

剖析程序中的栈与堆的内存分配

在计算机系统中,运行的应用程序的数据都保存在内存中,不同类型的数据所保存在的区域不同,应用程序中总共有五个内存区域: (1).栈区[stack]:由编译器自动分配并释放,一般存放函数的参数值,局部变量等 (2).堆区[heap]:由程序员分配和释放内存,如果程序员不释放,程序结束时,可能会由操作系统回收 (3).全局区[静态区][static]:全局变量和静态变量的存储是放在一起的,而该区又分为两种情况,一种是已初始化的,另一种是未初始化的,初始化的全局变量和静态变量存放在一块区域,未初始化的全

操作系统中的内存分配

数据类型对应字节数(32位,64位 int 占字节数) 一.程序运行平台       不同的平台上对不同数据类型分配的字节数是不同的.       个人对平台的理解是CPU+OS+Compiler,是因为:       1.64位机器也可以装32位系统(x64装XP):       2.32位机器上可以有16/32位的编译器(XP上有tc是16位的,其他常见的是32位的):       3.即使是32位的编译器也可以弄出64位的integer来(int64).       以上这些是基于常见的w

堆,栈内存分配 && 常量区

1题: 针对以下代码, 1 2 3 4 const char str1[] = "abc"; const char str2[] = "abc"; const char *p1 = "abc"; const char *p2 = "abc"; 判断下列说法哪个是正确的() 正确答案: A   你的答案: F (错误) str1和str2地址不同,P1和P2地址相同 str1和str2地址相同,P1和P2地址相同 str1和st

程序运行时三种内存分配策略

按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的. 静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求. 栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未

内存分配有哪些策略

1.内存分配有哪些策略 我们从编译原理讲起,不同的开发环境.开发语言都会有不同的策略.一般来说,程序运行时有三种内存分配策略:静态的.栈式的.堆式的 静态存储是指在编译时就能够确定每个数据目标在运行时的存储空间需求,因而在编译时就可以给它们分配固定的内存空间. 这种分配策略要求程序代码中不允许有可变数据结构的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间. 栈式存储栈式存储分配是动态存储分配,是由一个类似于堆栈的运行栈来实现的,和静态存储的分配方式相反. 

windows内存详解(一) 全面介绍Windows内存管理机制及C++内存分配实例

十分感谢MS社区的帖子,讲得很好~ http://social.technet.microsoft.com/Forums/zh-CN/2219/thread/afc1269f-fe08-4dc7-bb94-c395d607e536 (一):进程空间 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本文目的: 对Windows内存管理机制了解清楚,有效的利用C+