Java ArrayList 的内存分配如何工作?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23245386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 21:29:35  来源:igfitidea点击:

How does memory allocation of an ArrayList work?

javamemoryarraylist

提问by ruhungry

As far as I know, when we are creating an ArrayList:

据我所知,当我们创建一个ArrayList

ArrayList<String> list = new ArrayList<String>(SIZE);

The JVM reserves for it a contiguous part of memory. When we are adding new elements into our list, when number of elements reaches 75% of SIZEit reserves a new, contiguous part of memory and copies all of the elements.

JVM 为其保留了一块连续的内存。当我们向列表中添加新元素时,当元素数量达到 75% 时,SIZE它会保留一个新的、连续的内存部分并复制所有元素。

Our list is getting bigger and bigger. We are adding new objects and the list has to be rebuilt once again.

我们的名单越来越大。我们正在添加新对象,并且必须再次重建列表。

What happens now?

现在会发生什么?

The JVM is looking for a contiguous segment of memory, but it does not find enough space.

JVM 正在寻找连续的内存段,但找不到足够的空间。

The Garbage Collector can try to remove some unused references and defragment memory. What happens, if the JVM is not able to reserve space for new instance of list after this process?

垃圾收集器可以尝试删除一些未使用的引用并对内存进行碎片整理。如果在此过程之后 JVM 无法为列表的新实例保留空间,会发生什么情况?

Does it create a new one, using maximal possible segment? Which Exceptionwill be thrown?

它是否使用最大可能的细分创建了一个新细分?哪个Exception会被抛出?

I read this question Java: How ArrayList manages memoryand one of the answers is:

我读了这个问题Java:如何 ArrayList 管理内存,答案之一是:

Reference doesn't consume much space.but anyhow, some of space is used. When array is getting bigger, it could be a problem. We cannot also forget that we have got another things which use memory space.

引用不占用太多空间。但无论如何,使用了一些空间。当数组越来越大时,这可能是一个问题。我们也不能忘记我们还有其他使用内存空间的东西。

采纳答案by Denis Kulagin

If JVM is not able to allocate requested amount of memory it'll throw

如果 JVM 无法分配请求的内存量,它将抛出

OutOfMemoryError

That's it. Actually JVM memory allocation has only two possible outcomes:

就是这样。实际上JVM内存分配只有两种可能的结果:

  1. Application is given requested amount of memory.
  2. JVM throws OutOfMemoryError.
  1. 应用程序获得请求的内存量。
  2. JVM 抛出 OutOfMemoryError。

There is no intermediate options, like some amount of memoryis allocated.

没有中间选项,比如分配了一定数量的内存

It has nothing to do with ArrayList, it's a JVM issue. If you asking whether ArrayListsomehow manages this situation in a special way - then answer is "No, it does not." It just tries to allocate amount of memory it needs and lets JVM think about the rest.

它与ArrayList无关,这是一个 JVM 问题。如果您询问ArrayList是否以某种特殊方式管理这种情况 - 那么答案是“不,它没有”。它只是尝试分配它需要的内存量,让 JVM 考虑其余的。

回答by Russell Zahniser

This will throw an OutOfMemoryErroras soon as there is not enough heap space to allocate the new array.

OutOfMemoryError一旦没有足够的堆空间来分配新数组,这将抛出一个。

Garbage collection will always be done before this error is thrown. This will compact memory and eliminate all the arrays of smaller sizes that are no longer used. But there is no way to get around the fact that the old array, the new array, and all the contained objects need to all be in memory at once in order for the old contents to be copied into the new list.

垃圾收集将始终在抛出此错误之前完成。这将压缩内存并消除所有不再使用的较小尺寸的数组。但是无法避免旧数组、新数组和所有包含的对象都需要同时在内存中的事实,以便将旧内容复制到新列表中。

So, if your memory limit is 10 MB, and the array takes up 2 MB and is being sized up to 3 MB, and the strings take up 6 MB, then OOM will be thrown even though after this operation you will only have 3 + 6 = 9 MB in memory. One way to avoid this, if you want to run really close to memory limits with a huge array, is to size the array to the full size to begin with so that it never needs to resize.

因此,如果您的内存限制为 10 MB,并且数组占用 2 MB 并且大小高达 3 MB,并且字符串占用 6 MB,那么即使在此操作之后您将只有 3 + 6 = 9 MB 内存。避免这种情况的一种方法是,如果您想在非常接近内存限制的情况下使用巨大的数组运行,则将数组的大小调整为开始时的完整大小,这样它就永远不需要调整大小。

回答by Biswajit_86

In Java, the referrences to the object are stored in the contiguous memory. The actual objects can stay in a non contiguous manner. So for ex your array might have 10 objects, JVM only needs to reserve the memory for the object references, not the objects. So if each reference takes a Byte(approx not the correct value), but each object takes up a KB, and you have an array of 10 elements, JVm will try to reserve contguous memory of only 1*10 B i.e 10 B. The objects can reside in 10 different memory locations totalling 10KB. Remember that both the contiguous and non contiguous memory spaces are for the memory allocated to the thread.

在 Java 中,对对象的引用存储在连续内存中。实际对象可以以不连续的方式保留。因此,例如您的数组可能有 10 个对象,JVM 只需要为对象引用保留内存,而不是对象。因此,如果每个引用占用一个字节(大约不是正确的值),但每个对象占用一个 KB,并且您有一个包含 10 个元素的数组,JVm 将尝试保留仅 1*10 B 的连续内存,即 10 B。对象可以驻留在 10 个不同的内存位置,总共 10KB。请记住,连续和非连续内存空间都用于分配给线程的内存。

When it needs to resize the array, the JVM tried to find a contiguos array of the newer length. So if you want to resize the array from 10 to 20 elements, it would try to reserve a contiguous space of 20 KB(using the above example). If it finds this space, it will do a copy of the references from the old array to the new array. If it does not find this space, it will try to do a GC . If it still does not find the space it throws an OutofMemoryException.

当需要调整数组大小时,JVM 会尝试找到一个新长度的连续数组。因此,如果您想将数组从 10 个元素调整为 20 个元素,它会尝试保留 20 KB 的连续空间(使用上面的示例)。如果它找到了这个空间,它会将旧数组的引用复制到新数组。如果它没有找到这个空间,它会尝试做一个 GC 。如果它仍然没有找到空间,它会抛出一个 OutofMemoryException。

Therefore, at any time when you are resizing the array, the JVM needs to find a contiguos memory to store referrences of the new sized array. So if you want to extend the array to a size of say 1000 element, and each reference is a byte each , the JVm will try to find a contiguos memory of 1000* 1KB which is 1 MB. If it finds this memory, it will do a copy of the references, and mark the oldeer contiguos memory for GC , whenever GC runs the next time If it is not able to find the memory , it will try to do a GC, and if it still does not find the contiguos memory , it will throw a Out of memory exception

因此,在调整数组大小的任何时候,JVM 都需要找到一个连续的内存来存储新大小数组的引用。因此,如果您想将数组扩展到 1000 个元素的大小,并且每个引用都是一个字节,则 JVM 将尝试找到 1000* 1KB 的连续内存,即 1 MB。如果它找到了这块内存,它会做一个引用的副本,并将旧的连续内存标记为 GC ,每当 GC 下次运行时,如果找不到内存,它会尝试做一个 GC,如果它仍然没有找到连续的内存,它会抛出一个内存不足的异常

This is the code in ArrayList which does the resizing. http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.ensureCapacity%28int%29

这是 ArrayList 中用于调整大小的代码。 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.ensureCapacity%28int%29

回答by user3579257

I assume it will run out of memory since there will be no space to use in the case where JVM can extend array size.

我认为它会耗尽内存,因为在 JVM 可以扩展数组大小的情况下将没有空间可以使用。

回答by Abhinavece

The very first thing I want to correct is, When we are adding new elements into our list, when number of elements reaches 100%of SIZE it reserves a new, contiguous part of memory and copies all of the elements.

我要纠正的第一件事是,当我们向列表中添加新元素时,当元素数量达到SIZE 的100% 时,它会保留一个新的、连续的内存部分并复制所有元素。

New Size of ArrayList will be:

ArrayList 的新大小将是:

NewSize of ArrayList = (CurrentSize * 3/2) + 1

ArrayList 的 NewSize = (CurrentSize * 3/2) + 1

But going this way is never recommended, if we have idea how much objects needs to be stored then we can use following constructor of ArrayList:-

但是从不建议采用这种方式,如果我们知道需要存储多少对象,那么我们可以使用以下 ArrayList 构造函数:-

ArrayList ar = new ArrayList(int initialCapacity);

ArrayList ar = new ArrayList(int initialCapacity);

If our JVM couldn't specify enough contiguous space on heap for the ArrayList, At runtime we'll get

如果我们的 JVM 不能在堆上为 ArrayList 指定足够的连续空间,在运行时我们会得到

  • Runtime error: OutOfMemoryError
  • 运行时错误:OutOfMemoryError