【发布时间】:2019-02-13 23:32:35
【问题描述】:
如果你有一个数组
int arr[100];
这究竟是如何存储在一台显然使用虚拟内存运行的现代机器中的?
我知道我们必须对虚拟内存使用分页,因为数组是一个连续的块,如果我们有一个 4kb 的页面,这个数组arr 将适合 1 页。
但是这个页面是存储在磁盘还是 RAM 上?
【问题讨论】:
标签: java c operating-system virtual-memory
如果你有一个数组
int arr[100];
这究竟是如何存储在一台显然使用虚拟内存运行的现代机器中的?
我知道我们必须对虚拟内存使用分页,因为数组是一个连续的块,如果我们有一个 4kb 的页面,这个数组arr 将适合 1 页。
但是这个页面是存储在磁盘还是 RAM 上?
【问题讨论】:
标签: java c operating-system virtual-memory
总而言之,数据可能位于不同的位置,可能会自动更改(通过操作系统的操作),并且在正常程序中工作时,您通常不需要知道它。
首先,在源代码中声明数组这一事实并不一定意味着整个数组或任何数组都在内存中创建。编译器可能会以消除部分或全部数组的方式优化源代码。
但是,让我们假设数组是实际创建的。创建虚拟内存是为了呈现一种错觉,即进程独占使用物理内存和/或它拥有比实际可用的物理内存更多的内存。这种错觉的一个目的是进程不必关心他们的数据实际在哪里。而绝大多数正常进程都可以忽略这一点。
此外,在大多数情况下,编译器很少注意小对象相对于页面边界的放置位置。将 100 个 int 的数组放置为完全位于一页内还是跨越页边界通常几乎没有什么区别。
当有必要了解或影响数据的实际位置时,就会出现许多问题。
有一些方法可以影响数据相对于页面边界的位置,方法是为此目的使用系统或库调用,或者分配多余的内存,然后将数据放在其中的选定位置。
如果数据很重要并且首选或需要保留在物理内存中,则可能会有系统调用(当然取决于系统)来请求。
在没有此类特定请求的情况下,数据的位置取决于许多因素。如果你声明一个int的静态数组并用编译时数据初始化它,数据可能会出现在最终生成的可执行文件的一部分中。在某些系统中,当启动可执行文件时,系统不会将整个文件加载到内存中。它仅在引用可执行文件时才从可执行文件中加载数据的各个部分。因此,该数据最初可能驻留在磁盘上。加载到内存后,如果系统负担了其他需要内存的东西,系统可能会从内存中丢弃这些数据,使其再次只存在于磁盘上的可执行文件中。
另一方面,如果数据是在程序执行过程中产生的,那么程序产生的时候当然是在内存中。但是,如果系统有其他需求,系统可能会从内存中删除数据。在这种情况下,由于磁盘上不存在数据(就像可执行文件中的数据一样),数据首先写入磁盘上的页面或交换文件。
通常,数据所在的位置可能会随时间而变化。
【讨论】:
java 标记的,因此如果确实需要,您可以使用-XX:+AlwaysPreTouch 启动VM,以用零预先触摸每个页面。通常,如果某些数据在同一缓存行上,而不是在页面上,那么您通常会更关心(当然,如果您这样做的话)。
CPU CACHE 以便我们以后可以更快地访问?
我知道我们必须对虚拟内存使用分页。
您不必必须使用分页。您可以关闭分页。
如果我们有一个 4kb 的页面,这个数组
arr将适合 1 个页面。
它可能适合 4kb 页面,但它很可能不会在 4kb 边界上(或附近)对齐,因此实际上,它可能会跨两个页面存储。
此页面是存储在磁盘还是 RAM 上?
数组与其他数据结构没有什么不同。它们存储在内存 (RAM) 中,除非操作系统在内存不足时将其换出到 DISK。
【讨论】:
int 组成且对齐要求为八字节的数组分配给从潜在页面偏移的均匀分布中随机选择的位置的概率跨越页面边界的概率为 99 / (4096/8) = 99/512。对于四字节int,它是 99/1024。这个答案中关于数组“可能跨两页存储”的说法是不正确的。
int 是 4 个字节,所以不知道 "eight-byte int" 来自哪里,但你是对的,我读过int[100] 为 int[1000]。 int[100] 可能在一页内,而不是跨两页。