Java消耗的内存超过Xmx参数

时间:2018-02-14 23:44:11

标签: java jvm

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

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

java -Xmx5m -Xss5m -Xrs -Xint -Xbatch Test

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

我想知道30MB用于什么?

3 个答案:

答案 0 :(得分:5)

正如评论和答案所暗示的那样,还有许多其他因素需要考虑 测量JVM内存使用情况时的帐户。但是,我认为没有任何答案 足够深度。

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(Resident Set Size,或者这个进程使用了​​多少内存),我们看到了JVM的 进程使用大约23MB的内存。为了了解原因,让我们做一些分析。获得好的最快捷方式 概述是打开NativeMemorytracking使用jcmd工具的VM.native_memory命令。所以, 让我们再次运行我们的应用程序:

$ 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)

记忆区域

让我们分解 1

  • Java堆:这是堆 -
  • Class :这是 Metaspace ,假设您使用的是java 8。
  • 线程:这显示了线程的数量以及线程的整体内存使用情况(请注意,本节中使用的stack反映了Xss值乘以线程数,您可以使用-Xss获得默认的java -XX:+PrintFlagsFinal -version |grep ThreadStackSize值。
  • 代码:代码缓存 - JIT(即时编译器)使用它来缓存已编译的代码。
  • GC :垃圾收集器使用的空间。
  • 编译器:生成代码时JIT使用的空间。
  • 符号:这适用于符号,字段名称,方法签名等...
  • 本机内存跟踪:本机内存跟踪器本身使用的内存。
  • Arena Chunk :这与malloc竞技场 2 有关。

不仅仅是堆!

保留,已提交和RSS

请注意,每个地区都有committedreserved部分。保持简短 reserved是它可以增长的内容,committed是目前承诺使用的内容。 例如,请参阅Java Heap部分:Java Heap (reserved=2048KB, committed=2048KB)reserved是我们的 -Xmx值和承诺将是我们的-Xms value,在这种情况下它们是相等的。

另请注意,committed总大小 - 它没有 反映RSS报告的实际使用情况(或top中的RES列)。他们不同的原因是RSS显示 所有内存页面的大小已经并且仍在使用在物理内存中,而committed显示的内存是 用于包括不在物理记忆 3 中的那些。

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

  1. 请参阅https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr022.html
  2. 来自JVM本机内存跟踪文档(https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html#BABJGHDB):
  3.   

    Arena是使用malloc分配的一块内存。当退出作用域或留下代码区域时,内存将从这些块中大量释放。这些块可以在其他子系统中重用以保存临时存储器,例如,线程前分配。 Arena malloc策略确保没有内存泄漏。所以竞技场作为一个整体被跟踪,而不是单个对象。无法跟踪一些初始内存量。

    1. 为了解决RSS,保留和提交内存之间的区别太多了,操作系统内存管理是一个复杂的主题,但请参阅 this answer以获得良好的概览。

答案 1 :(得分:3)

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

答案 2 :(得分:1)

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