【问题标题】:How are arrays stored in Virtual Memory?数组如何存储在虚拟内存中?
【发布时间】:2019-02-13 23:32:35
【问题描述】:

如果你有一个数组

int arr[100];

这究竟是如何存储在一台显然使用虚拟内存运行的现代机器中的?

我知道我们必须对虚拟内存使用分页,因为数组是一个连续的块,如果我们有一个 4kb 的页面,这个数组arr 将适合 1 页。

但是这个页面是存储在磁盘还是 RAM 上?

【问题讨论】:

    标签: java c operating-system virtual-memory


    【解决方案1】:

    总而言之,数据可能位于不同的位置,可能会自动更改(通过操作系统的操作),并且在正常程序中工作时,您通常不需要知道它。

    首先,在源代码中声明数组这一事实并不一定意味着整个数组或任何数组都在内存中创建。编译器可能会以消除部分或全部数组的方式优化源代码。

    但是,让我们假设数组是实际创建的。创建虚拟内存是为了呈现一种错觉,即进程独占使用物理内存和/或它拥有比实际可用的物理内存更多的内存。这种错觉的一个目的是进程不必关心他们的数据实际在哪里。而绝大多数正常进程都可以忽略这一点。

    此外,在大多数情况下,编译器很少注意小对象相对于页面边界的放置位置。将 100 个 int 的数组放置为完全位于一页内还是跨越页边界通常几乎没有什么区别。

    当有必要了解或影响数据的实际位置时,就会出现许多问题。

    有一些方法可以影响数据相对于页面边界的位置,方法是为此目的使用系统或库调用,或者分配多余的内存,然后将数据放在其中的选定位置。

    如果数据很重要并且首选或需要保留在物理内存中,则可能会有系统调用(当然取决于系统)来请求。

    在没有此类特定请求的情况下,数据的位置取决于许多因素。如果你声明一个int的静态数组并用编译时数据初始化它,数据可能会出现在最终生成的可执行文件的一部分中。在某些系统中,当启动可执行文件时,系统不会将整个文件加载到内存中。它仅在引用可执行文件时才从可执行文件中加载数据的各个部分。因此,该数据最初可能驻留在磁盘上。加载到内存后,如果系统负担了其他需要内存的东西,系统可能会从内存中丢弃这些数据,使其再次只存在于磁盘上的可执行文件中。

    另一方面,如果数据是在程序执行过程中产生的,那么程序产生的时候当然是在内存中。但是,如果系统有其他需求,系统可能会从内存中删除数据。在这种情况下,由于磁盘上不存在数据(就像可执行文件中的数据一样),数据首先写入磁盘上的页面或交换文件。

    通常,数据所在的位置可能会随时间而变化。

    【讨论】:

    • 优秀的答案!由于这是用java 标记的,因此如果确实需要,您可以使用-XX:+AlwaysPreTouch 启动VM,以用零预先触摸每个页面。通常,如果某些数据在同一缓存行上,而不是在页面上,那么您通常会更关心(当然,如果您这样做的话)。
    • 那么,如果数组最初被创建,存储在 RAM 中并被访问,那么它是否存储在 CPU CACHE 以便我们以后可以更快地访问?
    • @BrijendarBakchodia:缓存通常由处理器自动管理。当处理器从主内存加载某些东西时,它通常会在缓存中保留一份副本以供将来加载或存储。当处理器将某些内容存储到内存中时,它也可能在缓存中创建一个副本。但是,缓存方案有许多变化,在评论中讨论太多,对于单个 Stack Overflow 问题来说可能太多了。通常当事物在缓存中时,它们是主存的副本;缓存中的数据不会从主存中删除。
    • 好的,我明白了。例如,是否可以在缓存中存储二叉树结构? struxt 有左右指针,所以我想每次都必须索引 tlb 成本很高。另一方面,数组是连续存储的,所以可以缓存?
    • @BrijendarBakchodia:缓存不是用来寻址和存储特定事物的内存。我只能建议您查找有关缓存如何工作的入门书、教科书和参考信息。对于 Stack Overflow cmets 来说,这个主题太大了。
    【解决方案2】:

    我知道我们必须对虚拟内存使用分页。

    您不必必须使用分页。您可以关闭分页。

    如果我们有一个 4kb 的页面,这个数组 arr 将适合 1 个页面。

    它可能适合 4kb 页面,但它很可能不会在 4kb 边界上(或附近)对齐,因此实际上,它可能会跨两个页面存储。

    此页面是存储在磁盘还是 RAM 上?

    数组与其他数据结构没有什么不同。它们存储在内存 (RAM) 中,除非操作系统在内存不足时将其换出到 DISK。

    【讨论】:

    • 一个由 100 个八字节 int 组成且对齐要求为八字节的数组分配给从潜在页面偏移的均匀分布中随机选择的位置的概率跨越页面边界的概率为 99 / (4096/8) = 99/512。对于四字节int,它是 99/1024。这个答案中关于数组“可能跨两页存储”的说法是不正确的。
    • @EricPostpischil int 是 4 个字节,所以不知道 "eight-byte int" 来自哪里,但你是对的,我读过int[100]int[1000]int[100] 可能在一页内,而不是跨两页。
    • 这是一个展示一般对象计算的示例。
    • 谢谢。我现在想知道如果我访问这个数组,它会存储在 CPU 缓存中以便下次访问可以快速吗?假设我在我的代码中线性扫描数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    • 2010-10-03
    • 2012-06-28
    • 1970-01-01
    • 2015-05-25
    • 2013-01-05
    • 2021-11-07
    相关资源
    最近更新 更多