问题描述:
在启动了一个TCP服务端接受并处理客户端请求。客户端创建了一个定时器每隔一定时间启动2000个TCP客户端线程去连接服务端。程序运行了一段时间后服务端报一下错误:
六月 08, 2016 1:36:58 下午 io.netty.util.internal.logging.Slf4JLogger warn
警告: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:949)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1360)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:132)
at com.bh.client.SendClient.send(SendClient.java:72)
at
......
并且有错误日志如下:
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 32756 bytes for ChunkPool::allocate
# 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 (allocation.cpp:211), pid=21316, tid=21348
#
# JRE version: Java(TM) SE Runtime Environment (7.0_75-b13) (build 1.7.0_75-b13)
# Java VM: Java HotSpot(TM) Client VM (24.75-b04 mixed mode, sharing windows-x86 )
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
--------------- T H R E A D ---------------
Current thread (0x01932400): VMThread [stack: 0x03ac0000,0x03b10000] [id=21348]
Stack: [0x03ac0000,0x03b10000], sp=0x03b0ed34, free space=315k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
......
VM_Operation (0x0bcfe9c0): BulkRevokeBias, mode: safepoint, requested by thread 0x06065c00
......
--------------- S Y S T E M ---------------
OS: Windows 8.1 Build 9600
CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 23 stepping 10, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, tsc
Memory: 4k page, physical 2096372k(337136k free), swap 4324596k(1038956k free)
vm_info: Java HotSpot(TM) Client VM (24.75-b04) for windows-x86 JRE (1.7.0_75-b13), built on Dec 18 2014 17:06:46 by "java_re" with unknown MS VC++:1600
time: Wed Jun 08 13:36:59 2016
elapsed time: 6032 seconds
问题分析:
这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。能创建的线程数的具体计算公式如下:
(MaxProcessMemory-JVMMemory-ReservedOsMemory)/ (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存
JVMMemory jvm内存大小
ReservedOsMemory 保留的操作系统内存
ThreadStackSize 线程栈的大小
当创建一个线程的时候,java虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存。
根据公式得到给JVM内存越多能创建的线程越少越容易发生java.lang.OutOfMemoryError: unable to create new native thread。
解决方案:
- 根据业务逻辑及时回收用完的线程。
- MaxProcessMemory 使用64位操作系统
- JVMMemory 减少JVMMemory的分配
- ThreadStackSize 减小单个线程的栈大小