我有一个非常简单的Web服务器类(基于Java SE的HttpServer
类)。
当我使用以下命令启动已编译的类并设置内存使用限制:
java -Xmx5m -Xss5m -Xrs -Xint -Xbatch Test
现在,如果我使用top
命令检查内存,则指示执行我的类的Java进程使用了约31MB的驻留内存。
我想知道那30MB的内存用于什么?
正如评论和答案所提到的,当测量JVM内存使用情况时,还有许多其他因素需要考虑。然而,我认为没有任何答案深入到足够的程度。
让我们直接回答"I was wondering what is that 30MB used for?"这个问题。为了解决这个问题,这里有一个简单的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:
stack
反映了Xss
值乘以线程数,您可以通过java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
获取默认的-Xss
值)。不仅仅是堆!
committed
和reserved
部分。简单来说,reserved
是它可以增长到的大小,而committed
是当前已经承诺使用的大小。例如,看一下Java Heap
部分:Java Heap (reserved=2048KB, committed=2048KB)
,reserved
是我们的-Xmx
值,而committed
则是我们的-Xms value
值,在这种情况下,它们是相等的。committed
大小并不反映RSS(或top
中的RES列)报告的实际使用情况。它们之间的差异在于RSS显示了所有仍在物理内存中使用的内存页面的大小,而committed
显示的是已经使用的内存,包括那些不在物理内存中的内存3。Arena是使用malloc分配的一块内存。当退出作用域或离开代码区域时,会批量释放这些内存,这些块可以在其他子系统中重复使用以保存临时内存,例如预线程分配。Arena malloc策略确保没有内存泄漏。因此,Arena被整体跟踪而不是单个对象。一些初始内存无法跟踪。
-Xmx5m仅用于堆内存,top命令会显示整个内存使用情况,包括JNI调用在进程中处理时使用的本地内存。
-Xmx
参数指定的是JVM堆的最大大小,而不是JVM使用的总内存大小。 - user207421