问题处理记录与深入:系统线程耗尽,Java无法调用native方法新建线程

1. 问题处理记录

1.1 问题描述

  • 公司使用Presto作为OLAP查询引擎,Presto的coordinator节点在运行过程中报错

    java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reachedat java.base/java.lang.Thread.start0(Native Method)at java.base/java.lang.Thread.start(Thread.java:802)
    
  • 当时,第一反应:有了异常堆栈,大概知道是哪里发生了线程滥用,这是测试环境,先立马重启服务后观察下线程增长情况

  • 重启服务后,不停执行如下命令,发现对应Java进程的线程使用量确实再不断增加

cat /proc/${pid}/status | grep "Threads"

1.2 问题修复与观察

  • 问题原因: 通过异常堆栈,发现是某个方法不停新建HttpClient、却又没有进行close导致

  • 问题修复后,通过如下shell脚本观察线程使用情况:每隔10min打印一次线程数

    #!/bin/bashwhile true
    doecho -ne $(date +%Y-%m-%dT%H:%M:%S)" "cat /proc/${pid}/status | grep "Threads" # 使用时,${pid}替换成对应的Java服务进程号sleep 10m
    done
    
  • 定时执行shell脚本,发现线程数得到了控制,观察4小时,最大线程数699 —— 问题成功修复

    nohup ./watch_threads.sh > threads_stat.txt 2>&1 &
    

    在这里插入图片描述

2. 疑问:一个Java进程究竟能创建多少线程?

  • 后来,使用ulimit -a查看系统资源配置时,发现系统允许root用户可以创建的最大进程或线程数为unlimited

  • 因此,笔者有了疑惑:

    • 既然是unlimited,为何会出现unable to create native thread的情况?
    • 还有,从系统资源有限的角度来说,这里的unlimited不应该是无上限,而是相对具体的、类似65636这样的固定值来说,只要系统资源未耗尽就可以创建线程
  • 可惜的是,笔者当时并未查看报错时的线程数,无法判断这个unlimited的上限究竟是多少

2.1 优秀文章的启发:How Many Threads Can a Java VM Support?

  • Baeldung的一篇文章:How Many Threads Can a Java VM Support?,让笔者大概有了一个认识
  • JVM,即一个Java进程,能创建的最大线程数,至少有两个方面的决定因素:
    • JVM本身 + 系统内存
    • 操作系统限制

2.2 决定因素1:JVM本身 + 系统内存

  • JVM中,堆栈的max size由-Xss-XX:ThreadStackSize进行设置
    -Xss1024k # 如果省略unit,默认unit:Byte
    -XX:ThreadStackSize=1024 # unit:KB
    
  • JVM会为每个线程创建自己的堆栈,创建堆栈使用的内存为系统内存,并非JVM Heap memory
  • 因此,有如下计算公式
    • MaxProcessMemory:是指进程的最大寻址空间
    • ReservedOsMemory:保留的操作系统内存,如Native Heap、JNI之类,一般100MB
    Number of threads = (MaxProcessMemory - JVMHeapMemory - ReservedOsMemory) / (ThreadStackSize) 
    

2.3 决定因素2:操作系统限制(以Linux系统为例)

  • 首先,Linux系统级对max thread的限制,threads-max

    cat /proc/sys/kernel/threads-max # 服务器上的threads-max = 6179160
    
  • 其次, Linux系统在内核级别将线程视为进程,因此限制最大进程数的pid_max也会影响JVM可以创建的线程数量

  • 这也是为什么ulimit -a展示的max user processes也被视为线程数限制的原因

    cat /proc/sys/kernel/pid_max # 相对threads-max,值更小,4194303
    
  • 还有,vm.max_map_count 参数,它指定进程可以拥有的虚拟内存区域 (VMAs,Virtual Memory Areas) 的最大数量

    cat /proc/sys/vm/max_map_count # 三者中,max_map_count的值最小,2097152
    
  • 最后,Linux支持针用户级别的资源限制,可以通过ulimit -a查看当前用户的资源限制。其中,max user processes的值也限制了JVM能创建的最大线程数

2.4 总结

  • JVM能创建的最大线程数是由各种因素综合决定的,且一定是这些因素中的min value决定
  • 决定因素1触发unable to create native thread,其根因是内存不足
  • 决定因素2中触发unable to create native thread,其本质是系统资源限制

3. 后记

  • 后续,如果有机会可以学习:
    • 如何触发unable to create native thread
    • 如何调整JVM参数、Linux系统的线程limit,从而验证这些影响因素
  • 一些优秀参考链接:
    • 启蒙文章:How Many Threads Can a Java VM Support?
    • unable to create new native thread 问题处理,指出了该出现错误的两种原因:内存不足达到线程数限制
    • Maximum Number of Threads per Process in Linux
    • How to Get the Number of Threads in a Java Process,可以学习如何通过ps命令查看线程数
    • 非常简单的触发unable to create native thread错误的demo:java jvm 最大线程数设置
    • 对决定因素1中计算公式的介绍:JVM最多能创建多少个线程: unable to create new native thread

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/38252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Google推出开源模型Gemma 2:性能大幅提升与创新训练方法

引言 近日,Google推出了开源模型Gemma 2,吸引了广大研究人员和开发者的关注。相比上一代模型,Gemma 2在性能和可用性方面实现了显著提升,提供了9B和27B两个版本,并且对外开放免费使用。本文将深入探讨Gemma 2的技术细…

架构师篇-10、DDD实战篇:通过领域模型落地系统

基于领域模型的设计与开发 数据库设计程序设计微服务设计 在线订餐系统的领域事件通知 微服务拆分 事件风暴会议 梳理领域事件进行领域建模识别聚合关系划分限界上下文 用户下单领域模型 更新后的模型 领域模型的设计实现过程 数据库设计 数据库映射:一对一关系…

SpringBoot使用redis 笔记(视频摘抄 哔哩哔哩博主(感谢!):遇见狂神)

springboot集成redis步骤 1.创建springboot项目 2.配置连接 3.测试 创建springboot项目 创建以一个Maven项目 创建之后查看pom.xml配置文件,可以看到 pom文件里面导入了 data-redis 的依赖,那我们就可以在知道,springboot集成redis操作…

计算机基础之汇编语言学习笔记

学习来源:b站各种学习资料 前置知识:计算机组成原理等知识 学习参考的资源 汇编语言编程的速成指南[上]~从零开始的期末抢救计划 (8086汇编)_哔哩哔哩_bilibili 链接: https://pan.baidu.com/s/1tg_ZW7VD3TS_s1v_EjS89w?pwdak6…

Uniapp 默认demo安装到手机里启动只能看得到底tab无法看到加载内容解决方案

Uniapp 默认demo安装到手机里以后,启动APP只能看到底tab栏,无法看到每个tab页对应的内容,HBuilder会有一些这样的报错信息: Waiting to navigate to: /pages/tabBar/API/API, do not operate continuously: 解决方案:…

分治精炼宝库-----快速排序运用(⌯꒪꒫꒪)੭

目录 一.基本概念: 一.颜色分类: 二.排序数组: 三.数组中的第k个最大元素: 解法一:快速选择算法 解法二:简单粗暴优先级队列 四.库存管理Ⅲ: 解法一:快速选择 解法二:简单粗…

Unity扩展编辑器功能的特性

1.添加分组标题 用于在Unity的Inspector视图中为属性或变量组创建一个自定义的标题或头部,有助于在Inspector中组织和分类不同的属性,使其更易于阅读和管理。 [Header("Common Properties")] public float MouseSensitivity 5; public float…

微服务中的Docker详细学习

Docker的个人理解 首先我对于Docker的理解分为两部分,第一是对名字上的理解,我们都知道docker的英文翻译是“码头工人”的意思,所以我们也可以理解为docker是码头上的一个个集装箱的使用。这也与他的图标很相似。其次我是对于其功能上的理解&…

Redis 高可用(理论)

目录 Redis 高可用 Redis 持久化 RDB 持久化 触发条件 手动触发 自动触发 ##其他自动触发机制## 执行流程 启动时加载 AOF 持久化 执行流程 (1)命令追加(append) (2)文件写入(write)和文件同步(sync) (3&…

帝国CMS(EmpireCMS)漏洞复现

简介 《帝国网站管理系统》英文译为Empire CMS,简称Ecms,它是基于B/S结构,且功能强大而帝国CMS-logo易用的网站管理系统。 帝国CMS官网:http://www.phome.net/ 参考相关漏洞分析文章,加上更详细的渗透测试过程。 参考…

snat、dnat和firewalld

目录 概述 SNAT源地址转换 DANT目的地址转换 抓包 firewalld 端口管理 概述 snat :源地址转换 内网——外网 内网ip转换成可以访问外网的ip 也就是内网的多个主机可以只有一个有效的公网ip地址访问外部网络 DNAT:目的地址转发 外部用户&#…

人工智能导论速成笔记

文章目录 前言考试题型第一章、人工智能导引 (10分 )课后习题第二章、Python基础 (10分 )*文件读写NumPy的使用Python绘图基础第三章、机器学习初步(15分 )逻辑回归分类(Logistic Regression)*,3.5线性回归预测(Linear Regression)*,3.6 、3.7、 3.8聚类 3.9第四章、自然语言…

一文带你了解乐观锁和悲观锁的本质区别!

文章目录 悲观锁是什么?乐观锁是什么?如何实现乐观锁?什么是CAS应用局限性ABA问题是什么? 悲观锁是什么? 悲观锁它总是假设最坏的情况,它会认为共享资源在每次被访问的时候就会出现线程安全问题&#xff0…

JVM调优(一)——JVM调优诊断工具详解

最近项目要生产上线,正在做压测性能测试,开始进行一些性能瓶颈分析,记得上一次做性能分析优化,还是国网项目,针对Kafka,Canal,ES,服务,数据库等一系列的排查分析,后面打算补一下总结内容&#x…

安全和加密常识(6)Base64编码方式

文章目录 什么是 Base64编码原理编解码示例应用什么是 Base64 Base64 是一种用于将二进制数据编码为仅包含64种ASCII字符的文本格式的编码方法,注意,它不是加密算法。它设计的目的主要是使二进制数据能够通过只支持文本的传输层(如电子邮件)进行传输。Base64常用于在需要处…

Windows系统下文件夹权限详解

文章目录 问题描述文件夹属性 问题描述 今天在Win10系统下,实现文件夹设置权限,具体的方案的涉及到我们公司内部的一款加密软件,不太方便透漏,借此机会,我也重新的回顾下windows系统下的文件夹权限 文件夹属性 打开…

vue3+Ts封装axios网络请求

1.安装axios npm i axios 在package.json中检查axios是否安装成功 "dependencies": {"axios": "^1.7.2","vue": "^3.4.29","vue-router": "^4.4.0"}, 2.新建文件 新建文件utils/request.ts import…

Java 并发编程常见问题

1、线程状态它们之间是如何扭转的? 1、谈谈对于多线程的理解? 1、对于多核CPU,多线程可以提升CPU的利用率; 2、对于多IO操作的程序,多线程可以提升系统的整体性能及吞吐量; 3、使用多线程在一些场景下可…

鸿蒙开发设备管理:【@ohos.multimodalInput.inputDevice (输入设备)】

输入设备 输入设备管理模块,用于监听输入设备连接、断开和变化,并查看输入设备相关信息。比如监听鼠标插拔,并获取鼠标的id、name和指针移动速度等信息。 说明: 本模块首批接口从API version 8开始支持。后续版本的新增接口&…

【算法专题--栈】用队列实现栈 -- 高频面试题(图文详解,小白一看就懂!!)

目录 一、前言 二、题目描述 三、解题方法 ⭐两个队列实现栈 🥝解题思路 🍍案例图解 ⭐用一个队列实现栈 🍇解题思路 🍍案例图解 四、总结与提炼 五、共勉 一、前言 用队列实现栈 这道题,可以说是--栈…