分配空闲内存的概念

时间:2010-07-30 18:35:14

标签: assembly memory-management malloc

我想知道最低级别的内存分配是如何工作的。例如,如果程序想要创建一些长数组或其他任何东西,它将如何询问内存,程序如何确保它不会占用与其他程序正在使用的内存相同的内存。

如果有人能为我带来一些启示,我将非常感激。

4 个答案:

答案 0 :(得分:3)

据我所知(至少在UNIX上),所讨论的程序会调用系统库中的内存(例如malloc和friends)。这些库在程序的虚拟地址空间中维护一个空闲内存块列表,并从该列表中清除内存(这是一个过于简单化的过程,它们维护此列表并处理字对齐,连续块等的方法相当复杂)。至于确保程序不接触彼此的存储器,OS具有虚拟存储器的概念,其基本上将每个程序的可寻址存储器映射到物理存储器的不同部分。有关详细信息,请参阅http://en.wikipedia.org/wiki/Virtual_memory

答案 1 :(得分:0)

可以通过多种方式分配内存......两种广泛的方式是静态和动态分配。

静态分配意味着程序可以使用的所有内存一次分配,并且最多可以使用该数量。

动态分配意味着当程序需要分配内存时,它会进入堆并将指针放在第一个可用的内存块上(根据使用的动态分配算法指定大小)。然后,因为它需要(例如在数组中)它需要更多,将指针保持在原始位置,因此它知道数组的开头在哪里。现代计算机通常可以很好地为应用程序分配包括内存在内的资源,从而降低了deadlock的可能性。在更高级别,当对象/数组/可以从内存中删除任何内容时,垃圾收集会处理此内存。

这里的问题是,当给出空闲内存并随意释放时,不同的程序可以获取不一定按顺序排列的不同块。这就是我们所说的碎片化(这就是为什么你不时地对磁盘驱动器进行碎片整理)。当以连续的方式分配内存时,可以更有效地读取内存。

有关于内存的大量信息,所以这里有一小部分数据供您在自己的内存中分配;)

Wiki Link to OSDev on Dynamic Allocation
Dynamic allocation in C++
Memory in C (This is kind of low level yet easy to understand)

快乐阅读!

答案 2 :(得分:0)

最简单的解决方案是不允许释放已分配的内存。假设操作系统有一堆内存,它知道可供程序分配。操作系统跟踪该空闲区域开头的地址。如果有足够的内存可用于第一个alloc,则alloc获取空闲指针地址,并且空闲指针向前移动alloc的数量。这继续向前推进,直到没有更多的内存或没有人再分配。因此,如果起始地址是0x1000并且有人想要0x20字节,则它们将返回0x1000作为alloc的指针并且空闲指针移动到0x1020。假设0x100的下一个分配返回0x1020,空闲指针移动到0x1120,等等。

您也可以从高地址向下工作,自上而下而不是自下而上。内存顶部可能是0x10000,第一次分配0x20导致0x10000-0x20 = 0xFFE0因此0xFFE0被发送到应用程序并且也被保存为可用内存的顶部。 0x100 alloc获得0xFEE0等。

这种简单化的想法,从不释放内存的问题在于,你的内存很快耗尽。到那个时候,如果已经完成的程序可能已经成为孤儿。所以它可能适用于某些嵌入式系统,但总的来说还有更多工作要做。

因此,与文件系统不同,必须由内存分配系统(操作系统)维护一个表,该系统至少包含为每个已发生的alloc分配的起始地址和数据量。然后某种搜索算法通过该列表尝试确定用于完成alloc的打开的内存块。当自由发生时,可能是一种简单的方式来查找具有匹配地址的条目并从表中删除它。使表结构快速解析,排序等等,但也允许小型和大型alloc,而不会浪费太多内存。

Mmus可以让这更容易,部分原因是它们已经由表驱动,硬件导航mmu表以找到物理地址等。这里的一大特色是,您可以在物理地址空间中获取彼此不相邻的内存块,但可以线性放置在虚拟地址空间中。所以你的应用程序可能需要12345个字节,而你的mmu系统可能有最小的内存分区为4kbytes,所以你只需要找到四个免费的内存块,不必彼此远离,你必须找到四个mmu表彼此相邻的条目,您可以将这四个mmu条目指向四个单独的物理条目,从而创建一个分配给该应用程序的16k字节空间。您仍然需要mmu系统之外的其他一些表,告诉您这四个mmu条目是同一分配空间的一部分。这与文件系统没有什么不同,在该文件系统中,12345字节文件可能存储在4个4096字节扇区中,这些扇区不一定在磁盘上彼此相邻。目录结构和文件系统表使用链接列表或一些其他方法来跟踪该文件所占用的扇区。

就内存的管理,选择什么样的物理地址等而言。经过几十年的操作系统,已经有无数的解决方案,无数小时的实验和研究。想想餐馆的主人。你进来三个人,想要一张桌子。您选择了多少种不同的方式?有时他们有一张图表和一支蜡笔,有时他们只是徘徊在休息区找一张桌子。您可能会或可能不会意识到,但有时他们不仅仅是试图找到任何四个顶级希望和绝望的六个顶部,但他们也试图平衡每个服务员/女服务员的客户数量。他们可能也试图留下大量的桌子,以防8人或10人参加,他们可以一起推桌子。对于许多不同的餐厅和主机,可能有许多不同的解决方案为您的派对分配一个桌子。同样,从早期的分时计算机到现在,存在许多不同的内存分配解决方案。

没有什么可以阻止你自己尝试这一点。编写一个占用大块内存的程序,并创建自己的malloc和自由例程,尝试将该块内存分开来为malloc提供服务并释放,并且可以使用随机函数并使用它来调用malloc和free例程。 / p>

答案 3 :(得分:0)

假设您从用户模式程序员的角度来看这个主题,这个答案分为两个部分:

  1. 用户模式部分 - malloc
  2. malloc()或类似的代码调用的东西将是一个用户模式库,通常管理堆数据结构。最简单的分配器将调用通常称为brk(...)的系统/内核函数,该函数返回所需大小的内存块。但是,每次你的应用程序想要内存时进行系统调用都很昂贵。所以你的malloc库从brk()中获取一大块并在堆中管理它并从那里返回小块。

    1. 内核模式部分 - sys_brk(在linux上)
    2. 这是brk的实现。在高级别,进程描述符具有构成其使用的地址空间的“存储区域”列表。 brk()基本上分配一个页面框架块来增长数据段。它如何分配页面框架以及对页面框架的讨论可能超出了这个问题的范围,但如果你想进一步研究,请问。