如何增加JVM线程的最大数量(Linux 64位)

21

我在一台有15G内存的Linux机器上无法创建超过32k个Java线程。


1
@guillaumegirod-vitouchkina 这是发生在负载测试的负载生成机器上的。由于第三方遗留库设计有缺陷,每个网络连接需要使用多个线程。随后线程数量迅速增加,但大部分线程处于空闲状态。 - maczniak
1
好的,我理解并且同情。 - guillaume girod-vitouchkina
3个回答

58
你可以使用示例程序来查找当前线程限制。
如果出现Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread错误,请检查以下内容:
  1. 在小内存机器上

    每个Java线程都会占用自己的堆栈内存。默认堆栈大小为1024k(= 1M)。你可以减少堆栈大小,例如java -Xss512k ...。如果堆栈大小太低,JVM将无法启动。

    同时要注意堆内存配置:(初始)-Xms和(最大)-Xmx。分配给堆的内存越多,可用于堆栈的内存就越少。

  2. 系统限制

    ulimit -a中的某些值可以影响线程限制。

    • max memory size - 在大多数64位机器上不受限制
    • max user processes - linux将线程视为进程
    • virtual memory - 在大多数64位机器上不受限制。虚拟内存使用由-Xss配置增加(默认为1024k)

    你可以通过(临时)运行ulimit命令或(永久)编辑/etc/security/limits.conf来更改这些值。

  3. sys.kernel.threads-max

    该值是系统全局的(包括非JVM进程)最大线程数。检查cat /proc/sys/kernel/threads-max,如果必要,增加该值。

    echo 999999 > /proc/sys/kernel/threads-max
    或者
    sys.kernel.threads-max = 999999/etc/sysctl.conf中进行永久更改。

  4. sys.kernel.pid_max

    如果cat /proc/sys/kernel/pid_max与当前限制相似,则需要增加此值。Linux将线程视为进程。

    要永久更改,可以执行以下操作之一:echo 999999 > /proc/sys/kernel/pid_max或在/etc/sysctl.conf中添加sys.kernel.pid_max = 999999

    您还可能需要增加sys.vm.max_map_count的值。可以通过执行cat /proc/sys/vm/max_map_count来检查其值,它应该至少为(2×线程数)。

    Attempt to protect stack guard pages failed.OpenJDK 64-Bit Server VM warning: Attempt to deallocate stack guard pages failed.错误信息由JavaThread::create_stack_guard_pages()发出,并调用os::guard_memory()。在Linux中,这个函数是mprotect()。

    要永久更改sys.vm.max_map_count的值,可以执行以下操作之一:echo 1999999 > /proc/sys/vm/max_map_count或在/etc/sysctl.conf中添加sys.vm.max_map_count = 1999999


我经过了几个解决方案,只有这个提供的答案才有效! - javaPhobic
1
我执行了配置 #sysctl -p,但出现了错误: "sys.kernel.threads-max" 是未知的关键字,"sys.kernel.pid_max" 是未知的关键字,"sys.vm.max_map_count" 是未知的关键字。 - Thoman
关于 -Xss 栈大小选项,有没有办法查看线程使用了多少堆栈空间?知道如何配置此值很好,但我想知道是否有 JMX 指标或其他东西可以告诉我我的平均和/或最大线程堆栈利用率,以便我可以决定是否实际上需要更改此值。 - Dasmowenator

17

针对现代 (systemd) linux 系统的额外信息。

有很多关于需要调整的值的资源(其他答案是大多数资源的良好来源);但是,通过 systemd "TasksMax" 限制实施了新的限制,它设置 cgroup 上的 pids.max。

对于登录会话,默认值为内核限制 pids_max 的 33%(通常为12,288)的UserTasksMax 可以在 /etc/systemd/logind.conf 中进行覆盖。

对于服务,默认值为内核限制 pids_max 的15%(通常为4,915)的DefaultTasksMax。您可以通过在“systemctl edit”中设置 TasksMax 或更新 /etc/systemd/system.conf 中的 DefaultTasksMax 来覆盖服务。


我花了很长时间才找到这个。终于!非常感谢! - Benjamin Marwell

5

我在一个 Python 程序中遇到了类似的问题,以下方法对我有效。这是基于上面 maczniak 的回答和 https://superuser.com/questions/1219960/cannot-edit-proc-sys-kernel-threads-max 的内容。

echo kernel.threads-max = 1073741823 >> /etc/sysctl.conf && echo 1073741823 > /proc/sys/kernel/threads-max
echo kernel.pid_max = 999999 >> /etc/sysctl.conf && echo 999999 > /proc/sys/kernel/pid_max
echo vm.max_map_count = 2147483646 >> /etc/sysctl.conf && echo 2147483646 > /proc/sys/vm/max_map_count
echo vm.overcommit_memory = 1 >> /etc/sysctl.conf && echo 1 > /proc/sys/vm/overcommit_memory
echo fs.inotify.max_user_instances = 256 >> /etc/sysctl.conf && echo 256 > /proc/sys/fs/inotify/max_user_instances
sysctl -p

我还需要在 /etc/systemd/system.conf(或对于用户运行的服务,是/etc/systemd/user.conf)中设置DefaultTasksMaxDefaultTasksMax=unlimited
Systemd还会对从登录Shell运行的程序施加限制。这些默认情况下每个用户有4096个(将增加至12288),并且在/etc/systemd/logind.conf的[Login]部分中配置为UserTasksMax。
以上来自这个StackExchange问题。将我的UserTasksMax设置为UserTasksMax=999999对我有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接