点击左上角蓝字,关注“锅外的大佬”
专注分享国外最新技术内容
1.概述
有没有想过为什么Java应用程序通过众所周知的-Xms和-Xmx调优标志消耗的内存比指定数量多得多?出于各种原因和可能的优化,JVM可以分配额外的本机内存。这些额外的分配最终会使消耗的内存超出-Xmx限制。
在本教程中,我们将列举JVM中的一些常见内存分配源,以及它们的大小调整标志,然后学习如何使用本机内存跟踪监视它们。
2.原生分配
堆通常是Java应用程序中最大的内存使用者,但还有其他人。除了堆之外,JVM还从本机内存中分配出一个相当大的块来维护类的元数据,应用程序代码,JIT生成的代码,内部数据结构等。在下面的部分中,我们将探讨其中的一些分配。
2.1. Metaspace(元空间)
为了维护有关已加载类的一些元数据,JVM使用名为Metaspace的专用非堆区域。在Java 8之前,被称为PermGen或Permanent Generation。Metaspace或PermGen包含有关已加载类的元数据,而不是它们的实例,它们保存在堆中。
这里重要的是堆大小配置不会影响元空间大小,因为Metaspace是一个堆外数据区。为了限制Metaspace大小,我们使用其他调优标志:
-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置最小和最大元空间大小
在Java 8之前,-XX:PermSize和-XX:MaxPermSize设置最小和最大PermGen大小
2.2. Threads(线程)
JVM中最耗费内存的数据区之一是堆栈,与每个线程同时创建。堆栈存储局部变量和部分结果,在方法调用中起着重要作用。
默认的线程堆栈大小取决于平台,但在大多数现代64位操作系统中,它大约为1 MB。此大小可通过-Xss调整标志进行配置。
与其他数据区域相比,当对线程数没有限制时,分配给堆栈的总内存实际上是无限制的。值得一提的是,JVM本身需要一些线程来执行其内部操作,如GC或即时编译。
2.3. Code Cache(代码缓存)
为了在不同平台上运行JVM字节码,需要将其转换为机器指令。执行程序时,JIT编译器负责此编译。
当JVM将字节码编译为汇编指令时,它