这是关于计算机科学的一个小道问题:ram是如何分配的?
例如,我使用Windows。我可以知道程序使用哪些地址吗? Windows如何分配内存?连续还是非连续? 在Linux操作系统上它是一回事吗?
而且,我可以使用程序访问整个ram吗? (我不相信,但......)
你知道关于这方面的任何好的讲座/文件吗?
答案 0 :(得分:7)
首先,当你想你正在分配RAM时,你真的不是。我知道这很令人困惑,但一旦你理解它是如何工作的,它就不复杂了。继续阅读。
RAM由操作系统在名为" pages"的单元中分配。通常,这意味着4kiB的连续区域,但是其他尺寸也是可能的(为了进一步复杂化,在现代处理器上支持"大页面"(通常在1-4MiB的数量级),并且操作系统可能具有与页面大小不同的分配粒度,例如Windows的页面大小为4kiB,粒度为64kiB。) 让我们忽略那些额外的细节,只考虑"页面"具有一个特定尺寸(4KiB)。
如果你分配和使用的区域大于系统的页面大小,你通常会不拥有连续的内存,但你仍然会看到它因为你的程序只能"思考"在虚拟地址中。实际上,您可能正在使用两个(或更多)完全不连续的页面,但它们似乎是。这些虚拟地址由MMU透明地转换为实际地址 此外,并非所有您认为已分配的内存必须始终存在于RAM中,并且相同的虚拟地址可能在不同时间对应于完全不同的RAM(例如,当页面被换出并稍后再次交换时) - 你的程序会在相同的地址看到它,但实际上它很可能在不同的RAM中。)
虚拟内存是一种非常强大的工具。虽然程序中的一个地址只能引用RAM中的[最多]一个物理地址(在特定页面中),但RAM的一个物理页面可以映射到程序中几个的不同地址,并且甚至在几个独立的计划中 例如,可以创建"循环"内存区域和共享库中的代码通常会加载到一个内存位置,但许多程序同时使用它们(并且它们将在这些不同的程序中具有不同的地址) )。或者,您可以使用该技术在程序之间共享内存,因此当一个程序写入某个地址时,另一个程序的内存位置中的值会发生变化(因为它的内存完全相同!)。
在较高的层面上,您向标准库询问内存(例如malloc
),标准库管理一个或多或少未指定方式保留的区域池(有许多不同的分配器)实现,他们都有共同点,你可以要求他们的内存,他们回馈一个地址 - 这是你认为你在没有时分配RAM的地方。)
当分配器需要更多内存时,它会要求操作系统保留另一个块。在Linux下,这可能是sbrk
和mmap
,在Windows下,这可能是VirtualAlloc
。
一般来说,你可以对内存做3件事,它在Linux和Windows(以及其他所有现代操作系统)下通常都是一样的,虽然使用的API函数不同,但还有一些细微差别。
你可以保留它,这或多或少都没有,除了逻辑上划分你的地址空间(只有你的过程关心它)。
接下来,您可以提交它,这也不会做太多,但它会在某种程度上影响其他进程。系统总共限制了它可以为所有进程提交的内存量(物理RAM加上页面文件大小),并且它会跟踪它。这意味着您提交的内存与另一个进程可以提交的限制相同。否则,再没有太多事情发生
最后,您可以访问内存。最后,这具有明显的效果。首次访问页面时,会发生故障(因为页面根本不存在!),操作系统要么从文件中提取一些数据(如果页面属于映射),要么清除某些页面(可能在第一次之后)将其保存到磁盘)。然后操作系统调整虚拟内存系统中的结构,以便在您访问的地址中看到RAM的物理页面。
从您的角度来看,这些都不可见。它只是通过魔法运作。
可以检查其地址空间中使用哪些区域的过程,并且可以(但有点无意义)将其转换为物理地址。注意,在不同时间运行的相同程序可以存储例如不同地址的一个特定变量。在Windows下,您可以使用VMMap工具检查进程内存分配。
如果您编写自己的操作系统,则只能使用所有RAM,因为操作系统保留的内存总是存在用户进程无法使用的内存。
否则你原则上可以使用[几乎]所有内存。但是,您是否可以直接使用那么多取决于您的进程是32位还是64位。现在的计算机通常具有比使用32位的地址更多的RAM,因此您需要使用地址窗口扩展或者您的进程必须是64位。此外,即使给定一定数量的RAM原则上可使用32位寻址,一些地址空间因素(例如fragentation,内核保留)可能会阻止您直接使用所有内存。
答案 1 :(得分:-2)
这是一个重要的问题。
RAM被分配为程序想要的。某些语言(如C或C ++)可以让您自己完成此操作。其他人,比如Java,将为你提供分配内存的可爱抽象。
我们分配内存因为我们想存储一些东西。 RAM是将变量等存储为电二进制信号的字面位置。
是的,很有可能知道程序使用了哪些地址。我相信有一些工具可以做到这一点。如果您正在编写C ++,则可以创建指向免费存储(大型内存库)上的地址的指针:int * i = new int;
。如果您想知道存储位置,只需std::cout << "int i is at " << i << "." << endl;
。
我不知道什么是连续的和非连续的(抱歉'回合懒惰),但快速搜索表明Windows是重叠群,而GNU / Linux则不是。大多数Windows内存位于所有抽象的基础上,位于免费商店,包含对象或数据结构。
是的,您可以使用程序访问(我相信)整个RAM。这听起来非常糟糕,但您所要做的就是自己更改指针地址,例如i ++;
(实际上是遍历数组的常见操作)。
我没有回顾过这些,但这些视频看起来相当可信: