Linux 上的 Java 内存不足,尽管有大量可用内存用于缓存

Linux 上的 Java 内存不足,尽管有大量可用内存用于缓存

我正尝试在 Red Hat Enterprise Linux Server 版本 6.5(Santiago)上启动一个进程,但由于无法分配足够的内存而失败。

# There is insufficient memory for the Java Runtime Environment to continue. 
# Cannot create GC thread. Out of system resources.
# An error report file with more information is saved as:

问题不在于 Java 应用程序本身 - 当我简单运行以下命令时也会出现错误:

java -版本

查看内存消耗:

免费-m

             total       used       free     shared    buffers     cached
Mem:         32069      31276        792          0        556      16948
-/+ buffers/cache:      13771      18297
Swap:         9325         38       9287

因此 Mem 报告称 32 Gb 内存中 31 Gb 已被使用,但应该有 18 Gb 可用内存被缓存使用。当进程请求内存时,操作系统是否不应该释放其中的一部分?

错误转储的详细信息是

#
# There is insufficient memory for the Java Runtime Environment to continue.
# Cannot create GC thread. Out of system resources.
# Possible reasons:
#   The system is out of physical RAM or swap space
#   In 32 bit mode, the process size limit was hit
# Possible solutions:
#   Reduce memory load on the system
#   Increase physical memory or swap space
#   Check if swap backing store is full
#   Use 64 bit Java on a 64 bit OS
#   Decrease Java heap size (-Xmx/-Xms)
#   Decrease number of Java threads
#   Decrease Java thread stack sizes (-Xss)
#   Set larger code cache with -XX:ReservedCodeCacheSize=
# This output file may be truncated or incomplete.
#
#  Out of Memory Error (gcTaskThread.cpp:46), pid=40816, tid=140071992215296
#
# JRE version: 6.0_26-b03
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.1-b02 mixed mode linux-amd64 compressed oops)

---------------  T H R E A D  ---------------

Current thread (0x00007f6508006800):  JavaThread "Unknown thread" [_thread_in_vm, id=40817,              stack(0x00007f650d46c000,0x00007f650d56d000)]

Stack: [0x00007f650d46c000,0x00007f650d56d000],  sp=0x00007f650d56b7c0,  free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x85ebd5]  VMError::report_and_die()+0x265
V  [libjvm.so+0x3e41b8]  report_vm_out_of_memory(char const*, int, unsigned long, char const*)+0x68
V  [libjvm.so+0x466ada]  GCTaskThread::GCTaskThread(GCTaskManager*, unsigned, unsigned)+0x13a
V  [libjvm.so+0x4655de]  GCTaskManager::initialize()+0x21e
V  [libjvm.so+0x465373]  GCTaskManager::GCTaskManager(unsigned)+0x13
V  [libjvm.so+0x722cad]  ParallelScavengeHeap::initialize()+0x4dd
V  [libjvm.so+0x836549]  Universe::initialize_heap()+0xa9
V  [libjvm.so+0x8360ea]  universe_init()+0x7a
V  [libjvm.so+0x4ac53b]  init_globals()+0x4b
V  [libjvm.so+0x81cc74]  Threads::create_vm(JavaVMInitArgs*, bool*)+0x214
V  [libjvm.so+0x51a7b0]  JNI_CreateJavaVM+0x80

答案1

查看 jvm 最小最大内存,您是否使用任何 Web 服务器?查看线程数、内存设置 - 对于 Tomcat,大多数都是 @server.xml。查看 Java Mission Controlhttp://www.oracle.com/technetwork/java/javaseproducts/mission-control/java-mission-control-1998576.html获得额外的见解。Linux 通常会保留更多内存以备请求时使用。对于 Linux 上的 Java,只有 JMC 之类的东西可以帮助您了解正在发生的事情。查看 JVM 的标准输出。

答案2

问题似乎与内存无关,而是与进程限制有关。我以该用户身份运行该进程的进程限制非常低,设置为 1024。

ulimit -u
1024

并且该用户运行的所有进程的线程数接近于:

ps -eLf | grep 'myuser' | wc -l
1022

答案3

我认为我们错过了另一个也会阻止新线程创建的限制,这就是内核.pid_max限制。

root@myhost:~# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.7 LTS
Release:    16.04
Codename:   xenial
root@myhost:~# uname -a
Linux myhost 4.4.0-190-generic #220-Ubuntu SMP Fri Aug 28 23:02:15 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

在我的系统中,这个限制是最低限制,因此它总是第一个被达到的限制,并成为我的问题的根本原因。

我发现至少在我的系统中,这个阈值 kernel.pid_max 是 32768。当我启动任何简单的 JVM 进程时,它会报告如下错误:

java/jstack/jstat ...
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Cannot create GC thread. Out of system resources.
# An error report file with more information is saved as:
# /root/hs_err_pid1390.log

检查内存,足够。

root@lascorehadoop-15a32:~# free -mh
              total        used        free      shared  buff/cache   available
Mem:           125G         11G         41G        1.2G         72G        111G
Swap:            0B          0B          0B

检查系统线程:

~# ps -eLf|wc -l
31506

但是我通过 ulimit 检查了系统限制:

root@myhost:~# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 515471
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 98000
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 515471
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

从 ulimit 输出中,我们可以看到当前线程数远小于最大用户进程限制。

事实上,达到的极限是kernel.pid_max

检查和调整非常容易: https://www.cyberciti.biz/tips/howto-linux-increase-pid-limits.html

答案4

“free -g” 将为您提供当前内存使用情况,如果内存不足,则增加物理 RAM 或增加交换空间。

如果您有足够的内存,那么下一步就是增加最大用户进程数。

更改 ulimit 配置(在末尾添加以下几行)

vi /etc/security/limits.conf

* 软 nproc 65535

* 硬 nproc 65535

* 软无文件 65535

* 硬盘无文件 65535

vi /etc/security/limits.d/90-nproc.conf * 软 nproc 65535

* 硬 nproc 65535

* 软无文件 65535

* 硬盘无文件 65535

相关内容