一、认识问题:

首先我们通过下面这个 测试程序 来认识这个问题:
运行的环境 (有必要说明一下,不同环境会有不同的结果):32位 Windows XP,Sun JDK 1.6.0_18, eclipse 3.4,
测试程序:

import java.util.concurrent.CountDownLatch;  

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); public HoldThread() {
this.setDaemon(true);
} public void run() {
try {
cdl.await();
} catch (InterruptedException e) {
}
}
}

  

不指定任何JVM参数,eclipse中直接运行输出,看到了这位朋友了吧:
i = 5602 
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:597)
    at TestNativeOutOfMemoryError.main(TestNativeOutOfMemoryError.java:20)

二、分析问题:

这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。能创建的线程数的具体计算公式如下: 
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads 
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory         JVM内存
ReservedOsMemory  保留的操作系统内存
ThreadStackSize      线程栈的大小

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

结合上面例子我们来对公式说明一下: 
MaxProcessMemory 在32位的 windows下是 2G
JVMMemory   eclipse默认启动的程序内存是64M
ReservedOsMemory  一般是130M左右
ThreadStackSize 32位 JDK 1.6默认的stacksize 325K左右
公式如下:
(2*1024*1024-64*1024-130*1024)/325 = 5841 
公式计算所得5841,和实践5602基本一致(有偏差是因为ReservedOsMemory不能很精确)

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

咦,有点背我们的常理,恩,让我们来验证一下,依旧使用上面的测试程序,加上下面的JVM参数,测试结果如下: 
ThreadStackSize      JVMMemory                    能创建的线程数
默认的325K             -Xms1024m -Xmx1024m    i = 2655
默认的325K               -Xms1224m -Xmx1224m    i = 2072
默认的325K             -Xms1324m -Xmx1324m    i = 1753
默认的325K             -Xms1424m -Xmx1424m    i = 1435
-Xss1024k             -Xms1424m -Xmx1424m    i = 452

完全和公式一致。

到这里其实你只需要明白,线程栈使用的内存是JVM以外的内存也可以说是本地内存,自然就明白上边的结论了
三、解决问题: 
1, 如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
2, 如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:
a, MaxProcessMemory 使用64位操作系统
b, JVMMemory   减少JVMMemory的分配
c, ThreadStackSize  减小单个线程的栈大小

最新文章

  1. 向mysql中插入Date类型的数据
  2. EF 延迟加载和预先加载
  3. .net之工作流工程展示及代码分享(预告)
  4. sqlserver 读取xml 字符串方法
  5. http流请求时,被请求站点HttpContext.Current为null?
  6. Lua和C之间的交互
  7. java 多线程2
  8. 【Android】MTK Android 编译命令
  9. Android应用解决65K方法数限制
  10. Java学习笔记之:Java数组
  11. squid3.0 隐藏 hearder 设置
  12. delphi 10.1 Berlin 中使用自带的 MD5 校验
  13. 关于H5在微信浏览器内自动转格式,导致不能正常打开的问题
  14. PHP中获取某个网页或文件内容的方法
  15. 存储引擎和表的操作(mysql中的数据类型、完整性约束)
  16. HBase的java客户端测试(一)---DDL操作
  17. Confluence 6 log4j 日志级别
  18. tensorflow(3):神经网络优化(ema,regularization)
  19. 1-微信小程序开发(安装软件和运行第一个微信小程序)
  20. 关于final static修饰的常量部署后没有更新的问题

热门文章

  1. 第四篇 HTTP请求返回状态码收集及解释
  2. python中web应用与mysql数据库交互
  3. Windows ,获取硬盘物理序列号(VC++)
  4. Vmware vSphere 开启嵌套虚拟化
  5. 【深度学习的实用层面】(一)训练,验证,测试集(Train/Dev/Test sets)
  6. JavaScript学习(2)call&apply&bind&eval用法
  7. React 之容器组件和展示组件相分离解密
  8. JVM调优(2)
  9. 第14讲:嵌入式SQL语言(基本技巧)
  10. C++:模板——函数模板1