万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • 大纲

  • 走近Java

  • 内存与垃圾回收

  • 字节码与类加载

  • 性能监控与调优

  • 监控与性能调优案例

    • JVM监控与性能调优案例概述
    • Tomcat堆溢出分析
    • 堆溢出
    • 方法区溢出
    • GC overhead limit exceeded
    • 线程溢出
      • 报错信息
      • 案例模拟
      • 分析及解决
    • 调整堆大小提高服务的吞吐量
    • JVM优化之JIT优化
    • 合理配置堆内存
    • CPU占用很高排查方案
    • G1并发执行的线程数对性能的影响
    • 调整垃圾回收器提高服务的吞吐量
    • 日均百万级订单交易系统如何设置JVM参数
    • 内存泄漏与内存溢出
  • Java虚拟机
  • 监控与性能调优案例
2022-03-18
目录

线程溢出

# 线程溢出

# 报错信息

java.lang.OutOfMemoryError : unable to create new native Thread

  • 出现这种异常,基本上都是创建了大量的线程导致的

# 案例模拟

说明:操作系统会崩溃,linux无法再进行任何命令,mac/windows可能直接关机重启。鉴于以上原因,建议在虚拟机进行测试。

示例代码:

public class TestNativeOutOfMemoryError {
    public static void main(String[] args) {
        for (int i = 0; ; i++) {
            System.out.println("i = " + i);
            new Thread(new HoldThread()).start();
        }
    }
}

class HoldThread extends Thread {
    CountDownLatch cdl = new CountDownLatch(1);

    @Override
    public void run() {
        try {
            cdl.await();
        } catch (InterruptedException e) {
        }
    }
}

运行结果:

i = 15241 
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 
        at java.lang.Thread.start0(Native Method) 
        at java.lang.Thread.start(Thread.java:717) 
        at TestNativeOutOfMemoryError.main(TestNativeOutOfMemoryError.java:9) 

# 分析及解决

方向一:JVM设置

  • 通过 -Xss 设置每个线程栈大小的容量

  • JDK 5.0 以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。

  • 正常情况下,在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在 3000~5000 左右。

  • 能创建的线程数的具体计算公式如下:

    (MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads

    MaxProcessMemory     指的是进程可寻址的最大空间 
    JVMMemory            JVM内存 
    ReservedOsMemory     保留的操作系统内存 
    ThreadStackSize      线程栈的大小 
    

    在Java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。

    所以,由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread

综上,在生产环境下如果需要更多的线程数量,建议使用64位操作系统,如果必须使用32位操作系统,可以通过调整Xss的大小来控制线程数量。

方向二:线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制:

  • /proc/sys/kernel/pid_max :系统最大pid值,在大型系统里可适当调大
  • /proc/sys/kernel/threads-max: 系统允许的最大线程数
  • maxuserprocess(ulimit -u) :系统限制某用户下最多可以运行多少进程或线程
  • /proc/sys/vm/max_map_count: max_map_count文件包含限制一个进程可以拥有的VMA(虚拟内存区域)的数量。虚拟内存区域是一个连续的虚拟地址空间区域。在进程的生命周期中,每当程序尝试在内存中映射文件,链接到共享内存段,或者分配堆空间的时候,这些区域将被创建。 调优这个值将限制进程可拥有VMA的数量。限制一个进程拥有VMA的总数可能导致应用程序出错 ,因为当进程达到了VMA上线但又只能释放少量的内存给其他的内核进程使用时,操作系统会抛出内存不足的错误。如果你的操作系统在NORMAL区域仅占用少量的内存,那么调低这个值可以帮助释放内存给内核用。
#JVM监控与性能调优案例
上次更新: 5/28/2023, 10:57:53 PM
调整堆大小提高服务的吞吐量

调整堆大小提高服务的吞吐量→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式