Java Virtua Machine
Java 虚拟机
虚拟机组成部分:
-类加载子系统 Class Loader SubSystem
将编译好的Class文件加载到JVM中
-执行引擎
- 即时编译器
- 垃圾回收器
-本地接口库 Native Interface Library
调用操作系统本地方法库完成具体指令
-运行时数据区 Runtime Data Area
- 程序计数器
- 方法区
1.7时使用永久代实现,1.8中,数据被分到了元数据区和堆中,元空间存储类的元信息,静态变量和常量池等并入堆中。其中元空间不属于JVM内存区域,属于本地内存
类名,访问修饰符,常量池,字段描述,方法描述 - 虚拟机栈
栈帧:局部变量表,操作数栈,动态链接,方法出口 - 本地方法区
- 堆
Java程序的运行过程:
1.Java源文件被编译器编译成字节码文件
2.JVM将字节码文件编译成相应操作系统机器码
每种操作系统的解释器都是不同的,但基于解释器实现的虚拟机是相同的,这也是JAVA能够跨平台的原因
3.机器码调用响应操作系统的本地方法库执行相应的方法。
在一个Java进程开始运行后,虚拟机就开始实例化了,有多个进程启动就会实例化多个虚拟机。进程退出或关闭,虚拟机消亡。多个虚拟机之间不能共享数据。
–
Java 运行时数据区
- 程序计数器(线程私有)
- 虚拟机栈(线程私有)
- 本地方法区(线程私有)
- 方法区
- 堆
- 直接内存
线程私有区域的生命周期与线程相同,随线程的启动而创建,随线程的结束而销毁。在JVM内,每个时线程都与操作系统本地线程直接映射,因此这部分内存区域的存在与否和本地线程的启动销毁对应。
线程共享区域随JVM的启动而创建,随JVM的关闭而销毁。
直接内存
也叫堆外内存,他不是JVM运行时数据区的一部分,但在并发编程中被频繁使用。JDK的NIO模块就是基于堆外内存,NIO通过调用本地方法直接在操作系统上分配堆外内存。
程序计数器(线程私有区域)
一块很小的内存空间,用于存储当前运行线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器。方法正在执行时,记录的是实时虚拟机字节码指令的地址。如果是Native方法,则程序计数器为空Undefined。唯一一块没有OOM(Out of Memory)的区域。
虚拟机栈(线程私有区域)
虚拟机栈是描述Java方法执行过程的内存模型,它在当前栈帧中存储了局部变量表,操作数栈,动态链接,方法出口等。
我们平常写的递归方法就是离用了虚拟机栈,他的栈帧为我们保存了运行数据。
每个方法的运行和返回都对应了入栈和出栈。每个运行的线程只有一个栈帧处于活动状态。
本地方法区(线程私有区域)
作用和虚拟机栈类似,但本地方法栈是Native方法使用的区域。
堆(线程共享区域)
JVM运行过程中创建的对象和产生的数据都被存储在堆中。堆是线程共享区域,也是垃圾回收的主要区域。
因为JVM采用分代收集法,堆还能被分为:
- 新生代1/3
-Eden区8/30
-ServivorFrom区1/30
-ServivorTo区1/30
- 老年代2/3
- 永久代(1.7之前,方法区的实现,1.8之后仅有静态变量和常量池留在堆中,类的元信息被放到本地内存的元空间中)
新生代
JVM新创建的对象会被放在新生代
老年代
新生代达到一定寿命,或者创建时就占空间大的对象被放在老年代。
永久代(元数据区):存储已被虚拟机加载的类信息(Class),常量,静态变量,即时编译器编译后的代码等数据