概述
虽然这篇文章的标题打着JVM源码分析的旗号,不过本文不仅仅从JVM源码角度来分析,更多的来自于Linux Kernel的源码分析,今天要说的是JVM里比较常见的一个问题
这个问题可能有几种表述
一个Java进程到底能创建多少线程?
到底有哪些因素决定了能创建多少线程?
java.lang.OutOfMemoryError: unable to create new native thread的异常究竟是怎么回事
不过我这里先声明下可能不能完全百分百将各种因素都理出来,因为毕竟我不是做Linux Kernel开发的,还有不少细节没有注意到的,我将我能分析到的因素和大家分享一下,如果大家在平时工作中还碰到别的因素,欢迎在文章下面留言,让更多人参与进来讨论
从JVM说起
线程大家都熟悉,new Thread().start()即会创建一个线程,这里我首先指出一点new Thread()其实并不会创建一个真正的线程,只有在调用了start方法之后才会创建一个线程,这个大家分析下Java代码就知道了,Thread的构造函数是纯Java代码,start方法会调到一个native方法start0里,而start0其实就是JVM_StartThread这个方法
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
...
// We could also check the stillborn flag to see if this thread was already stopped, but
// for historical reasons we let the thread detect that itself when it starts running
jlong size =
java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
// Allocate the C++ Thread structure and create the native thread. The
// stack size retrieved from java is signed, but the constructor takes
// size_t (an unsigned type), so avoid passing negative values which would
// result in really large stacks.
size_t sz = size > 0 ? (size_t) size : 0;
native_thread = new JavaThread(&thread_entry, sz);
...
if (native_thread->osthread() == NULL) {
...
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"unable to create new native thread");
}
Thread::start(native_thread);
JVM_END
从上面代码里首先要大家关注下最后的那个if判断if (native_thread->osthread() == NULL),如果osthread为空,那将会抛出大家比较熟悉的unable to create new native thread OOM异常,因此osthread为空非常关键,后面会看到什么情况下osthread会为空
另外大家应该注意到了native_thread = new JavaThread(&thread_entry, sz),在这里才会真正创建一个线程
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
Thread()
#ifndef SERIALGC
, _satb_mark_queue(&_satb_mark_queue_set),
_dirty_card_queue(&_dirty_card_queue_set)
#endif // !SERIALGC
{
if (TraceThreadEvents) {
tty->print_cr("creating thread %p", this);
}
initialize();
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);
// Create the native thread itself.
// %note runtime_23
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
os::java_thread;
os::create_thread(this, thr_type, stack_sz);
}
上面代码里的os::create_thread(this, thr_type, stack_sz)会通过pthread_create来创建线程,而Linux下对应的实现如下:
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
}
// set the correct thread state
osthread->set_thread_type(thr_type);
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
thread->set_osthread(osthread);
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// stack size
if (os::Linux::supports_variable_stack_size()) {
// calculate stack size if it's not specified by caller
if (stack_size == 0) {
stack_size = os::Linux::default_stack_size(thr_type);
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be
// changed with the flag -Xss
assert (JavaThread::stack_size_at_create() > 0, "this should be set");
stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
pthread_attr_setstacksize(&attr, stack_size);
} else {
// let pthread_create() pick the default value.
}
// glibc guard page
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
}
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
pthread_attr_destroy(&attr);
if (ret != 0) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
if (lock) os::Linux::createThread_lock()->unlock();
return false;
}
// Store pthread info into the OSThread
osthread->set_pthread_id(tid);
...
}
...
return true;
}
如果在new OSThread的过程中就失败了,那显然osthread为NULL,那再回到上面第一段代码,此时会抛出java.lang.OutOfMemoryError: unable to create new native thread的异常,而什么情况下new OSThread会失败,比如说内存不够了,而这里的内存其实是C Heap,而非Java Heap,由此可见从JVM的角度来说,影响线程创建的因素包括了Xmx,MaxPermSize,MaxDirectMemorySize,ReservedCodeCacheSize等,因为这些参数会影响剩余的内存
阅读全文直接点击:
http://click.aliyun.com/m/9556/
分享到:
相关推荐
这个资源包含的"SimpleThread"源码很可能是对Java基础线程操作的一个实例演示。下面将详细解释多线程的基本概念、创建方法以及相关的知识点。 1. **线程的概念**:线程是操作系统分配CPU时间的基本单位,一个进程...
JDK自带了一系列强大的诊断工具,如jps(Java进程查看器)、jstat(统计信息工具)、jinfo(配置信息工具)、jmap(内存映射工具)、jhat(堆转储分析工具)和jstack(线程堆栈跟踪工具)。熟练掌握这些工具的使用,...
- JVM启动后会创建一个`java.exe`进程,并在这个进程中创建至少两个线程:主线程和垃圾回收线程。 - **主线程**:执行应用程序中的`main`函数中的代码。 - **垃圾回收线程**:负责清理主线程运行过程中在堆内存中...
在Java中,每个Java虚拟机(JVM)实例都有一个主线程,可以通过创建额外的线程来执行并发任务。 2. **线程的创建** - Java提供了多种创建线程的方式,如通过实现Runnable接口或继承Thread类。推荐使用实现...
在计算机科学领域,Java虚拟机(JVM)是Java语言的核心组成部分,它为Java程序提供了一个跨平台的运行环境。当涉及到嵌入式系统时,这种特性变得更加重要,因为这些系统通常具有资源有限的特性。本文将探讨嵌入式...
本文将对名为MammothCopy的Java开发源码进行深入探讨,旨在揭示其工作原理和关键知识点。 一、Java远程文件传输基础 1. Java的Socket编程:MammothCopy的核心技术之一就是利用Java的Socket编程实现客户端与服务器...
综上所述,解决“Java进程CPU占用率高”问题需要从多个角度出发,包括但不限于代码优化、JVM调优、垃圾收集策略调整、监控与诊断工具的使用等。通过系统性地分析和改进,可以有效地降低Java进程对CPU的占用,提高...
本文将深入探讨Java线程相关的知识,包括线程的创建、线程同步和通信、线程状态以及如何利用工具进行线程分析。 1. **线程的创建** Java提供了两种创建线程的方式: - 通过实现`Runnable`接口。创建一个类实现`...
JAVA源码,媒体网络,山寨QQ,Java聊天程序 Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构, 当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
"基于Java的源码-lobby(经典board游戏 Domination)" 提供的是开发一个名为“lobby”的游戏的源代码,这款游戏是基于经典的board游戏“Domination”。 【board游戏】 Board游戏是指在二维平面上进行的策略游戏,...
最后,我们提到"jvm-profiler-master"是一个源码包,意味着你可以深入研究其内部实现,学习如何构建这样的监控工具,或者根据自身需求进行二次开发。开源项目的特性也使得这个工具拥有良好的社区支持,遇到问题时...
在源码分析过程中,还会涉及到Java的多线程技术,以实现异步操作,如接收消息、更新界面等。Java提供了Thread类和Runnable接口来创建和管理线程,同时ExecutorService和Future接口提供了更高级的线程池管理。 此外...
其次,`jconsole`是一个图形化的JVM监视工具,它可以提供内存使用情况、线程信息、类加载情况等实时数据。开发者可以通过jconsole连接到本地或远程的Java进程,直观地看到各种性能指标,并进行诊断。此外,jconsole...
Java通过`Thread`类提供了线程的创建和管理,同时JVM还提供了一些内置线程,如垃圾收集线程。 其次,书中会介绍Java并发工具类,包括`ExecutorService`、`Future`、`Callable`、`Semaphore`、`CyclicBarrier`、`...
通过深入研究这个源码,学习者可以了解到Java在构建CRM系统时的具体应用,如数据库连接、MVC架构的应用、事务管理、多线程处理等,这对于提升Java开发者在企业级应用开发中的技能是非常有价值的。同时,也能理解和...
它能够实时显示JVM的运行信息,包括内存使用情况、线程状态、类加载、垃圾收集、CPU使用率等,为开发者提供了一个直观的界面,方便快速定位问题。 二、jvisualvm的主要功能 1. **内存监控**:jvisualvm可以展示堆...
- **jstack工具**:用于查看Java进程的线程堆栈信息,帮助分析线程状态。 以上是Java线程学习的一些核心知识点,理解和掌握它们对于进行高效并发编程至关重要。在实际开发中,还需要结合具体场景灵活运用,确保...
Java虚拟机栈也是线程私有的,它描述的是Java方法执行的内存模型:每个方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存储了方法中局部变量,...
6. **Java Management API (JMAPI)**:这是一个标准的API,允许开发者创建和注册管理 beans 来获取系统级别的信息,如网络连接、磁盘空间、进程信息等。 7. **Java诊断工具**:如JDK自带的`jinfo`、`jmap`、`jstack...