数组内存分配 – 分页

不确定Java,C#和C ++的答案是否相同,所以我对它们进行了分类。 所有语言的答案都会很好。

我一直在思考的所有日子,如果我分配数组,所有单元格都将位于一个连续的空间中。 因此,如果系统中没有足够的内存,则会出现内存不足exception。

没事,我说的是什么? 或者是否有可能,分配的数组将被分页?

C ++数组是连续的,这意味着内存具有连续的地址,即它在虚拟地址空间中是连续的。 它不需要在物理地址空间中是连续的,因为现代处理器(或它们的存储器子系统)具有将虚拟页面与物理页面相关联的大映射。 以用户模式运行的进程永远不会看到其数组的物理地址。

我认为在实践中大多数或所有Java实现都是相同的。 但程序员永远不会看到数组元素的实际地址,只是对数组的引用和索引它的方法。 因此从理论上讲,Java实现可能会破坏数组并在[]运算符中隐藏该事实,尽管JNI代码仍然可以以C ++样式查看数组,此时需要一个连续的块。 这假设JVM规范中没有关于数组布局的内容,jarnbjo告诉我没有。

我不知道C#,但我希望情况与Java非常相似 – 您可以想象一个实现可能会使用[]运算符来隐藏数组在虚拟地址空间中不连续的事实。 一旦有人获得指针,伪装就会失败。 [编辑:Polynomial说C#中的数组可能是不连续的,直到有人将它们固定为止,这是有道理的,因为你知道在将对象传递给使用地址的低级代码之前必须先固定对象。

请注意,如果您分配一些大型对象类型的数组,那么在C ++中,数组实际上是端到端放置的许多大型结构,因此连续分配所需的大小取决于对象的大小。 在Java中,对象数组“实际上”是一个引用数组。 所以这是一个比C ++数组更小的连续块。 对于本地类型,它们是相同的。

在C#中,您不能保证内存块是连续的。 CLR尝试在一个连续的块中分配内存,但它可以在几个块中分配它。 关于CLR如何管理C#内存几乎没有明确的行为,因为它被设计为被托管构造抽象掉。

它在C#中唯一真正重要的是你是通过P / Invoke将数组作为指针传递给某些非托管代码,在这种情况下你应该使用GC.Pin来锁定对象在内存中的位置。 在这种情况下,也许其他人将能够解释CLR和GC如何处理连续内存的需求。

没事,我说的是什么?

确实,在Java和C#中,但只有在达到流程或系统限制时,C ++才会出错。 不同的是,在Java和C#中,应用程序对自身施加了限制。 在C ++中,操作系统强加了限制。

或者是否有可能,分配的数组将被分页?

这也是可能的。 但是在Java中,对页面进行分页会对性能造成很大影响。 GC运行时,所有检查的对象必须在内存中。 在C ++中它不是很好,但影响较小。

如果您想要可以在Java中分页的大型结构,可以使用ByteBuffer.allocateDirect()或内存映射文件。 这可以通过在堆上使用内存来实现(基本上是C ++使用的)

在java的情况下,Array实现为Object ….
和对象只在堆中获得m / m …
所以我不完全肯定但是……只在RAM中制作….

你可以检查.. IBM M / m

在C(++)程序中通常(即,除非我们讨论解释代码而不是编译它并直接执行它),否则数组在虚拟地址空间中是连续的(当然,如果在有问题的平台)。

在那里,如果一个大数组不能连续分配,即使有足够的可用内存,你将获得std :: bad_allocexception(在C ++中)或NULL(来自malloc() – 类似于C / C ++中的函数或非抛出C ++中的operator new)。

虚拟内存(以及对磁盘的分页)通常不能解决虚拟地址空间碎片问题,或者至少不能直接解决,其目的是不同的。 它通常用于让程序认为有足够的内存,而实际上却没有。 RAM可以通过可用磁盘空间进行有效扩展,但代价是性能较低,因为当存在内存压力时,操作系统必须在RAM和磁盘之间交换数据。

您的arrays(部分或全部)可以通过操作系统卸载到磁盘。 但这对您的程序是透明的,因为无论何时需要从arrays访问某些内容,操作系统都会将其加载回来(再次,部分或全部,如操作系统认为必要)。

在没有虚拟内存的系统上,没有虚拟到物理地址转换,你的程序将直接与物理内存一起工作,因此,它必须处理物理内存碎片,并且还要与其他程序竞争空闲内存和地址空间,一般情况下,分配失败的可能性更大(具有虚拟内存的系统通常在单独的虚拟地址空间中运行程序,而应用程序A的虚拟地址空间中的碎片不会影响应用程序B的碎片)。

用Java和C#肯定。 我们可以通过运行byte[] array = new byte[4097];来certificate这一点byte[] array = new byte[4097]; 在Windows机器上,内存页面大小为4096bytes。 因此必须在一页以上。

当然,分页会影响性能,但这可能是使用.NET或Java等框架的GC可能具有优势的情况之一,因为GC是由知道分页发生的人编写的。 结构中仍然有优势使其更有可能在同一页面上具有相关元素(支持通过指针追逐集合的数组支持集合)。 这在CPU高速缓存方面也具有优势。 (大型数组仍然是导致GC崩溃的最佳方法之一,因为GC非常擅长这样做,它仍然会胜过许多其他处理相同问题的方法)。

几乎可以肯定,使用C ++,因为我们通常在操作系统的内存管理级别编码 – 数组位于连续的虚拟空间(无论是堆还是堆栈),而不是连续的物理空间。 在C或C ++中,可以在低于该值的级别进行编码,但这通常只能由实际编写内存管理代码本身的人来完成。