对于我的应用程序,Java进程使用的内存远远超过堆大小.
容器正在运行的系统开始出现内存问题,因为容器占用的内存比堆大小多得多.
堆大小设置为128 MB(-Xmx128m -Xms128m),而容器最多占用1 GB内存.在正常情况下,它需要500MB.如果docker容器具有以下限制(例如mem_limit=mem_limit=400MB),则该进程被OS的内存不足杀死所杀死.
你能解释为什么Java进程使用比堆更多的内存吗?如何正确调整Docker内存限制?有没有办法减少Java进程的堆外内存占用?
我使用JVM中的本机内存跟踪命令收集有关该问题的一些详细信息.
从主机系统,我获得容器使用的内存.
$ docker stats --no-stream 9afcb62a26c8
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
9afcb62a26c8 xx-xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.0acbb46bb6fe3ae1b1c99aff3a6073bb7b7ecf85 0.93% 461MiB / 9.744GiB 4.62% 286MB / 7.92MB 157MB / 2.66GB 57
Run Code Online (Sandbox Code Playgroud)
从容器内部,我获得进程使用的内存.
$ ps -p 71 -o pcpu,rss,size,vsize
%CPU RSS SIZE VSZ
11.2 486040 580860 3814600
Run Code Online (Sandbox Code Playgroud)
$ jcmd 71 VM.native_memory
71:
Native Memory Tracking:
Total: reserved=1631932KB, committed=367400KB
- Java Heap (reserved=131072KB, …Run Code Online (Sandbox Code Playgroud) 场景:
我有一个在docker容器中运行的JVM.我使用两个工具进行了一些内存分析:1)top 2)Java Native Memory Tracking.这些数字看起来很混乱,我试图找出导致差异的原因.
题:
对于Java进程,RSS报告为1272MB,报告的总Java内存为790.55 MB.我怎么能解释内存的其余部分1272 - 790.55 = 481.44 MB去哪了?
为什么我想在SO上查看这个问题后仍然保持这个问题的开放性:
我确实看到了答案,解释也很有道理.但是,从Java NMT和pmap -x获取输出后,我仍然无法具体映射实际驻留和物理映射的Java内存地址.我需要一些具体的解释(详细步骤)来找出导致RSS和Java Total提交内存之间差异的原因.
最高输出
Java NMT
Docker内存统计信息
图表
我有一个运行48小时以上的码头集装箱.现在,当我看到一个图表包含:
那么,在1.1 GB(RSS)和800 MB(Java Total committed memory)之间占用的内存是什么?
JDK版本是热点8u_45
我研究了我的 java 进程的本机内存。本机内存甚至比堆消耗更多的空间。然而,有许多本机内存块让我感到困惑。例如 pmap -x 的结果:
00007f8128000000 65508 25204 25204 rw--- [ anon ]
00007f812bff9000 28 0 0 ----- [ anon ]
00007f812c000000 65508 24768 24768 rw--- [ anon ]
00007f812fff9000 28 0 0 ----- [ anon ]
00007f8130000000 65508 25532 25532 rw--- [ anon ]
00007f8133ff9000 28 0 0 ----- [ anon ]
00007f8134000000 65524 22764 22764 rw--- [ anon ]
00007f8137ffd000 12 0 0 ----- [ anon ]
00007f8138000000 65508 26456 26456 rw--- [ anon ]
00007f813bff9000 …Run Code Online (Sandbox Code Playgroud) 我在docker容器内的Java 8上运行了一个java应用程序.该过程启动Jetty 9服务器并部署Web应用程序.传递以下JVM选项:-Xms768m -Xmx768m.
最近我注意到这个过程耗费了大量的内存:
$ ps aux 1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
app 1 0.1 48.9 5268992 2989492 ? Ssl Sep23 4:47 java -server ...
$ pmap -x 1
Address Kbytes RSS Dirty Mode Mapping
...
total kB 5280504 2994384 2980776
$ jcmd 1 VM.native_memory summary
1:
Native Memory Tracking:
Total: reserved=1378791KB, committed=1049931KB
- Java Heap (reserved=786432KB, committed=786432KB)
(mmap: reserved=786432KB, committed=786432KB)
- Class (reserved=220113KB, committed=101073KB)
(classes #17246)
(malloc=7121KB #25927)
(mmap: …Run Code Online (Sandbox Code Playgroud) 我正在 java 8 上运行不同 jvm 选项的实验,以降低 RSS:
用于 Rss 跟踪的脚本:
ps -o rss -o vsz -o pid $pid
用于设置 Java 进程的 JVM 参数:
-XX:+PrintNMTStatistics -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=detail
使用 jcmd 获取基线:
jcmd $pid VM.native_memory baseline
使用 jcmd 获取差异:
jcmd $pid VM.native_memory summary.diff
输出(部分线程区域):
- Thread (reserved=130696KB -21564KB, committed=130696KB -21564KB)
(thread #121 -21)
(stack: reserved=130048KB -21504KB, committed=130048KB -21504KB)
(malloc=379KB -67KB #610 -105)
(arena=268KB +7 #240 -42)
Run Code Online (Sandbox Code Playgroud)
问题:上面输出的 RSS 将考虑什么内存,是committed还是reserved?
我有一个非常简单的Web服务器类(基于Java SE的HttpServer类).
当我使用此命令启动编译的类来限制内存使用时:
java -Xmx5m -Xss5m -Xrs -Xint -Xbatch Test
现在,如果我使用top命令检查内存,则表示执行我的类的Java进程使用~31MB的驻留内存.
我想知道30MB用于什么?
MemoryMXBean.getHeapMemoryUsage()
我有一个使用 -Xms512m -Xmx512m 运行的 jvm 进程,下面显示了该进程的 MemoryMXBean.getHeapMemoryUsage() :
init = 512M
used = 105M
comitted = 491M
max = 491M
Run Code Online (Sandbox Code Playgroud)
此过程的MemoryMXBean.getNonHeapMemoryUsage() MemoryMXBean.getNonHeapMemoryUsage():
init = 2M
used = 25M
comitted = 25M
max = 0M
Run Code Online (Sandbox Code Playgroud)
-Xms
-Xms(初始堆大小)是什么意思?我曾经认为初始堆大小是jvm启动时jvm实际从os分配多少内存,但事实证明是错误的。顶部显示该 jvm 的 RES 接近 150m,但该 jvm 是使用 -Xms512M 运行的。
下面的公式正确吗(或者几乎正确-_-)?如果不是,还应该考虑什么?
total memory a jvm used = used of MemoryMXBean.getHeapMemoryUsage()
+ used of MemoryMXBean.getNonHeapMemoryUsage()
+ the direct memory we used in application level
Run Code Online (Sandbox Code Playgroud)
任何事情都会受到赞赏!
我们正在监控 jvm 指标,如堆、元空间、线程和 gc 计数,我们能够将这些指标推送到监控服务器,如 prometheus。类似地,我们想跟踪 Java 本机内存指标(jcmd VM.sumary 的输出)。我的问题是,是否可以通过调用任何 jvm 运行时类来获取这些指标?
我使用以下代码来测试最大线程数,但这很奇怪。
import java.util.concurrent.atomic.AtomicInteger;
public class TestThread extends Thread {
private static final AtomicInteger count = new AtomicInteger();
public static void main(String[] args) {
try{
while (true) {
(new TestThread()).start();
}
} catch (Error | Exception e) {
System.out.println(e.getMessage());
}
}
@Override
public void run() {
System.out.println(count.incrementAndGet());
while (true)
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
操作系统为ubuntu:18.04,内存为4G,处理器数为2。JDK:openjdk1.8.0_252
java -Xss1m -Xms1024m -Xmx1023m TestThread
java -Xss512k -Xms1024m -Xmx1023m TestThread
java -Xss1m -Xms2048m -Xmx2048m TestThread
结果,线程数始终等于第 10000 个左右。
jvm ×10
java ×9
memory ×4
linux ×3
docker ×2
pmap ×2
apache-spark ×1
jcmd ×1
monitoring ×1
prometheus ×1