【问题标题】:Java heap memory allocation limitsJava 堆内存分配限制
【发布时间】:2021-11-23 13:54:00
【问题描述】:

我编写了以下测试来检查最大可用堆内存:

import java.util.*;
public class Memory {
    public static void main(String[] args) {
        long maxMB = Runtime.getRuntime().maxMemory() / 1048576L;
        System.out.println("Maximum memory is " + maxMB + " MB.");
        ArrayList<byte[]> allocated = new ArrayList<>();
        try {
            while (true)
                allocated.add(new byte[1024*1024]);
        } catch (OutOfMemoryError e) {
            System.out.println("allocated " + allocated.size() + " MB before running out of memory.");
        }
    }
}

但是,当我对此进行测试时,似乎实际上只能分配一半的“可用”内存:

$ java -Xmx512m Memory 
Maximum memory is 512 MB.
allocated 255 MB before running out of memory.
$ java -Xmx1024m Memory 
Maximum memory is 1024 MB.
allocated 511 MB before running out of memory.

有人知道为什么会这样吗?

【问题讨论】:

  • 可能是因为 jvm 无法为您的阵列找到连续的内存块?
  • 我不知道为什么。但是我做了一些测试,一次增加100Kb,或者一次增加10Mb,然后使用内存分析工具(MAT),发现实际分配的内存量增加了(100Kb =>95%的使用率, 10Mb => 80% 使用率)。我认为@JustanotherJavaprogrammer 有道理。我还用LinkedList 替换了ArrayList 并得到了相同的结果。
  • @zysaaa 对链表很奇怪。那绝对没有那个需要。
  • 你可能会在@JustanotherJavaprogrammer那里找到一些东西。当我使块大小足够小时,它或多或少会耗尽整个内存。尽管内存管理器的性能如此糟糕,但仍然很奇怪。
  • 这有点道理:Java 中的内存管理器针对对象进行了优化,对象往往偏小。缓冲区等有一些更大的数组,但它们往往是少数(或早期分配的)。您分配几乎完全“大”数组的示例可能非常不典型。其他需要许多数组缓冲区的应用程序倾向于使用本机内存。可能是因为这个原因。

标签: java memory


【解决方案1】:

我相信内存管理器会尝试在下一个可用的 1MB 边界对齐块。但由于 1MB 数组实际上占用了略多于 1MB 的空间(用于存储长度和其他内容),因此它们之间的间隔几乎为 1MB。当块大小减少 16 字节时,它们突然又用完了整个内存。

【讨论】:

    猜你喜欢
    • 2010-12-26
    • 1970-01-01
    • 2020-03-20
    • 2011-02-16
    • 2019-03-05
    • 2023-01-13
    • 2011-05-28
    • 2018-10-22
    相关资源
    最近更新 更多