当前位置: 首页 > 知识库问答 >
问题:

Java比Xmx参数消耗更多内存

充普松
2023-03-14

我有一个非常简单的Web服务器类(基于JavaSE的HttpServer类)。

当我使用此命令启动编译后的类以限制内存使用时:

java-Xmx5m-Xss5m-Xrs-Xint-Xbatch测试

现在,如果我使用top命令检查内存,它表明执行我的类的Java进程使用了大约31MB的驻留内存。

我想知道那30MB是用来做什么的?


共有3个答案

长孙逸仙
2023-03-14

-Xmx5m仅用于堆内存,top将显示整个内存,包括进程内处理的JNI调用使用的本机内存。

夹谷星剑
2023-03-14

Java在虚拟机上运行,而不是直接在硬件上运行。这意味着这台机器需要自己的内存才能运行。您允许的5MB程序可能意味着Java虚拟机(JVM)正在使用另一个26MB。

袁奇逸
2023-03-14
匿名用户

正如评论和答案所暗示的,在测量JVM内存使用时还有许多其他因素需要考虑。然而,我认为任何答案都没有深入到足够的深度。

让我们回答“我想知道那30MB是用来做什么的?”正面。为此,这里有一个简单的java类:

// HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello world!");
        Thread.sleep(10000); // wait 10 seconds so we can get memory usage
    }
}

现在用堆约束编译并运行它:

$ nohup java -Xms2m -Xmx2m HelloWorld & # run in background
$ ps aux | awk 'NR==1; /[H]elloWorld/'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chaospie  6204  6.0  0.1 2662860 23040 pts/2   Sl   19:15   0:00 java -Xms2m -Xmx2m HelloWorld

看看上面的RSS(驻留集大小,或者这个进程使用了多少内存),我们可以看到JVM的进程使用了大约23MB的内存。为了了解原因,让我们做一些分析。获得良好概述的最快方法是启用NativeMemorytracking,使用jcmd工具的虚拟机。本机内存命令。那么,让我们再次运行我们的应用程序:

$ nohup java -XX:NativeMemoryTracking=summary -Xms2M -Xmx2M HelloWorld &
[2] 6661
nohup: ignoring input and appending output to 'nohup.out'

$ ps aux | awk 'NR==1; /[H]elloWorld/'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
chaospie  6661  5.0  0.1 2662860 23104 pts/2   Sl   19:21   0:00 java -XX:NativeMemoryTracking=summary -Xms2M -Xmx2M HelloWorld

$ jcmd 6661 VM.native_memory summary
6661:

Native Memory Tracking:

Total: reserved=1360145KB, committed=61177KB
-                 Java Heap (reserved=2048KB, committed=2048KB)
                            (mmap: reserved=2048KB, committed=2048KB)

-                     Class (reserved=1066093KB, committed=14189KB)
                            (classes #402)
                            (malloc=9325KB #146)
                            (mmap: reserved=1056768KB, committed=4864KB)

-                    Thread (reserved=20646KB, committed=20646KB)
                            (thread #21)
                            (stack: reserved=20560KB, committed=20560KB)
                            (malloc=62KB #110)
                            (arena=23KB #40)

-                      Code (reserved=249632KB, committed=2568KB)
                            (malloc=32KB #299)
                            (mmap: reserved=249600KB, committed=2536KB)

-                        GC (reserved=10467KB, committed=10467KB)
                            (malloc=10383KB #129)
                            (mmap: reserved=84KB, committed=84KB)

-                  Compiler (reserved=132KB, committed=132KB)
                            (malloc=1KB #21)
                            (arena=131KB #3)

-                  Internal (reserved=9453KB, committed=9453KB)
                            (malloc=9421KB #1402)
                            (mmap: reserved=32KB, committed=32KB)

-                    Symbol (reserved=1358KB, committed=1358KB)
                            (malloc=902KB #86)
                            (arena=456KB #1)

-    Native Memory Tracking (reserved=143KB, committed=143KB)
                            (malloc=86KB #1363)
                            (tracking overhead=57KB)

-               Arena Chunk (reserved=175KB, committed=175KB)
                            (malloc=175KB)

让我们把它分解为:

  • Java堆:这是堆-
  • 类:这是元空间,假设您使用的是java 8
  • 线程:这显示了线程的数量和线程的总体mem使用情况(注意,本节中使用的堆栈反映了Xss值乘以线程数量,您可以使用java-XX:PrintFlagsFinal-version | grep ThreadStackSize获得默认的Xss值)
  • 代码:代码缓存-JIT(即时编译器)使用它来缓存编译后的代码
  • GC:垃圾收集器使用的空间
  • 编译器:JIT在生成代码时使用的空间
  • 符号:用于符号、字段名、方法签名等
  • 本机内存跟踪:本机内存跟踪器本身使用的内存
  • 竞技场区块:这与马洛克竞技场2有关

不仅仅是堆!

注意,每个区域都有一个提交的部分和一个保留的部分。简而言之,保留的是它可以增长到的内容,提交的是当前要使用的内容。例如,请参阅Java堆部分:Java堆(保留=2048KB,提交=2048KB)保留的是我们的-Xmx值,提交的将是我们的-Xms值,在这种情况下,它们相等。

还要注意的是,总提交的大小-它不反映RSS报告的实际使用情况(或top中的RES列)。它们不同的原因是,RSS显示了物理内存中已经使用并仍在使用的所有内存页面的大小,而提交的显示了使用的内存,包括不在物理内存中的内存3

这还有很多,但是JVM和操作系统内存管理是一个复杂的主题,所以我希望这至少能在较高的层次上回答您的问题。

  1. 请参见https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr022.html

Arena是使用malloc分配的内存块。当退出范围或离开代码区域时,内存会从这些块中批量释放。这些块可以在其他子系统中重复使用以保存临时内存,例如线程前分配。Arena malloc策略确保没有内存泄漏。因此Arena作为一个整体而不是单个对象被跟踪。一些初始内存不能被跟踪。

 类似资料:
  • 关于Java应用程序使用的驻留内存,我有两个问题。 一些背景细节: 我用-xms2560m-xmx2560m设置了一个java应用程序。 java应用程序在容器中运行。k8s允许容器最多消耗4GB. 堆:应用程序的工作方式似乎是使用所有内存,然后释放,然后使用等等。 这张快照说明了这一点。Y列是空闲堆内存。(由应用程序通过)提取) 我还可以使用HotSpotDiagnosticMXBean来确认它

  • 我注意到Spring Boot应用程序不服从通过Xmx选项设置的内存量。例如:java-Xss64m-Xmx64m-jartest.jar 我还在控制台上打印了应用程序在启动时实际使用的内存量,并显示:最大内存:61M 当我在访问任何网页之前打开Windows进程时,它会显示-105M,那么Java怎么能说61M呢? 在访问任何网页后,它从-125M变为-135M。为什么会有这样的增长?它应该给出

  • 我编写的java应用程序遇到了一个问题,导致硬件性能问题。问题(我很确定)是,我运行应用程序的一些机器只有1GB的内存。当我启动java应用程序时,我将堆大小设置为-xms512m-xmx1024m。 我的第一个问题是,我的假设是否正确,因为我将机器的所有内存分配给java堆,这显然会导致性能问题?

  • 问题内容: 具有100个属性的一个对象所消耗的存储空间是否与每个具有一个属性的100个对象所消耗的存储空间相同? 为一个对象分配多少内存? 添加属性时会使用多少额外空间? 问题答案: 指出,这不是一个容易回答的简单问题: JVM可以自由地以内部或大端或小端的任何方式存储数据,并具有一定的填充或开销,尽管基元必须表现得好像它们具有官方大小一样。 例如,JVM或本机编译器可能会决定将64位长块(如)存

  • Android Studio在Mac机上消耗了太多的内存,并且还运行了多java进程。 Android Studio版本:使用Android Studio北极狐2020.3.1(补丁1构建#AI-203.7717.56.2031.7621141,构建于2021年8月7日) 当我面临内存不足的问题时,我正在监视Android Studio的内存消耗,我注意到多个“Java”进程正在运行,甚至一个进程

  • 我正在docker中运行一个java进程。我已经设置了xms(388m)和xmx(388m)。在应用程序启动后的某个时候,容器的内存消耗超过并达到了大部分~主机内存大小,容器被杀死。 < li >当我使用jprofiler连接到java进程时,我看到堆小于Xmx < li >但是,容器内顶部的命令显示< code>docker stats显示的内容 < li >当我在主机上运行相同的java进程时