JVM 简述
java通过编译.java
源文件文件生成.class
字节码文件,然后字节码文件通过java虚拟机的解释器,生成机器码来执行。
.java -> 编译器 -> .class -> jvm解释器 -> 机器码
Java之所以能跨平台,是因为每种平台的解释器不同,但实现的虚拟机是相同的。当一个程序运行,虚拟机就会开始实例化,多个程序运行会创建多个虚拟机,每个虚拟机之间的数据都不共享。当程序退出或停止,虚拟机实例消亡。
线程
jvm允许一个应用并发的执行多个线程,Hotspot JVM中的java线程与原生操作系统的线程有直接映射关系。
当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好后,就会创建一个操作系统原生线程。java线程结束,原生线程随之被收回。
操作系统负责调度所有线程,把它们分配到任何可用的cpu上。当原生线程初始化完毕,就会调用java线程的run()
方法。当线程结束,会释放所有java线程和原生线程资源。
Hotspot JVM 后台运行的主要线程有以下几个:
name | detail |
---|---|
虚拟机线程(VM Thread) | 这个线程等待jvm到达安全点操作出现。这些操作都必须在独立的线程内执行,因为当堆修改无法进行时,线程都需要jvm位于安全点。这些操作的类型有stop-the-world垃圾回收、线程栈dump、线程暂停、线程偏向锁(biased locking)解除。 |
周期性线程任务 | 负责定时器事件(也就是中断),用来调度周期性操作的执行 |
GC线程 | 这些线程支持jvm中不同的垃圾回收活动 |
编译器线程 | 这些线程动态的将字节码文件编译成本地平台的机器码 |
信号分发线程 | 这些线程接收发送到jvm的信号,并调用适当的jvm方法来处理 |
jvm内存区域
jvm 内存区域主要分为:线程私有区域:[虚拟机栈,程序计数器,本地方法区]。线程共享区:[堆,方法区(jdk8中取消了方法区,替换成了metaspace),直接内存(direct memory)]。
线程私有数据区域的生命周期与用户线程相同,依赖用户线程 启动/停止
而 创建/销毁
。(在hotspot jvm 中每个线程都与操作系统本地线程对应,因此这部分内存区域是否存在和本地线程生/死对应)
线程共享区域随虚拟机的 启动/停止
而 创建/销毁
。
程序计数器 Program Counter Register(线程私有)
一块较小的内存空间,是线程所有执行的字节码的信号指示器,每一条线程都有一个独立的程序计数器,这类内存称为线程私有内存。
程序计数器记录的是java方法的虚拟机字节码指令地址(当前指令的地址)。执行的native方法会记录在本地方法区,此时程序计数器为空。
程序计数器是虚拟机内存中,唯一一个没有被限制 OutOfMemoryError
的区域。