一、jvm运行流程
二、运行时数据区
1.方法区
- 方法区是所有线程共享的内存区域,它用于存储已被Java虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码等数据。
- 它有个别命叫Non-Heap(非堆)。当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常。
- 在JDK8以前,使用永久代的方式来实现方法区,JDK8以后,永久代的概念被废弃了,方法区改用在本地内存中实现的元空间(Meta Space)来代替,好处是元空间会在运行时根据需要动态调整,只要没有超过当前进程可用的内存上限(32位和64位系统各不相同),就不会出现溢出的问题
-
类型信息包括什么?
1、类型的全名(The fully qualified name of the type) 2、类型的父类型全名(除非没有父类型,或者父类型是java.lang.Object)(The fully qualified name of the typeís direct superclass) 3、该类型是一个类还是接口(class or an interface)(Whether or not the type is a class ) 4、类型的修饰符(public,private,protected,static,final,volatile,transient等)(The typeís modifiers) 5、所有父接口全名的列表(An ordered list of the fully qualified names of any direct superinterfaces) 6、类型的字段信息(Field information) 7、类型的方法信息(Method information) 8、所有静态类变量(非常量)信息(All class (static) variables declared in the type, except constants) 9、一个指向类加载器的引用(A reference to class ClassLoader) 10、一个指向Class类的引用(A reference to class Class) 11、常量池(The constant pool for the type)
2.堆
- JVM中的堆是用来存放对象的内存空间,几乎所有的Java对象、数组都存储在JVM的堆内存中。
- 堆内存的存储特点:先进先出,后进后出
- 堆是JVM占用区域最大的一块,并且在运行时动态地分配内存大小
- 线程共享,整个 Java 虚拟机运行过程中只会有一个堆,所有的线程都访问同一个堆。而JVM中的程序计数器、Java 虚拟机栈、本地方法栈都是一个线程对应一个。
- 虚拟机启动的时候创建堆。
- 堆是JVM中涉及垃圾回收的主要场所。
- 堆可分为新生代(Eden 区:From Survior,To Survivor)、老年代。
- JVM规范规定堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。
- 关于 Survivor(幸存区) s0,s1 区: 复制之后有交换,谁空谁是 to。
3.程序计数器
- 程序计数器是一块较小的内存空间,它可以看作是:保存当前线程所正在执行的字节码指令的地址(行号)
- 由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储。称之为“线程私有”的内存。程序计数器内存区域是虚拟机中唯一没有规定OutOfMemoryError情况的区域。
4.Java虚拟机栈
- java虚拟机是线程私有的,它的生命周期和线程相同。
- 虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 每虚拟机栈中是有单位的,单位就是栈帧,一个方法一个栈帧。一个栈帧中他又要存储,局部变量,操作数栈,动态链接,出口等。
解析栈帧:
- 局部变量表:是用来存储我们临时8个基本数据类型、对象引用地址、returnAddress类型。(returnAddress中保存的是return后要执行的字节码的指令地址。)
- 操作数栈:操作数栈就是用来操作的,例如代码中有个 i = 6*6,他在一开始的时候就会进行操作,读取我们的代码,进行计算后再放入局部变量表中去
- 动态链接:假如我方法中,有个 service.add()方法,要链接到别的方法中去,这就是动态链接,存储链接的地方。
- 出口:出口是什呢,出口正常的话就是return 不正常的话就是抛出异常落
5. 本地方法栈
- 本地方法栈的功能和JVM栈非常类似,区别在于虚拟机栈执行的是Java方法,本地方法栈执行的是本地(Native)方法服务,存储的也是本地方法的局部变量表,本地方法的操作数栈等信息。
- 栈的存取类型为类似于水杯,先进后出。
- 栈内的数据在超出其作用域后,会被自动释放掉,它不由JVM GC管理。
- 每一个线程都包含一个栈区,每个栈中的数据都是私有的,其他栈不能访问。
- 本地方法栈是在 程序调用 或 JVM调用 本地方法接口(Native)时候启用。
- 本地方法都不是使用Java语言编写的,它们可能由C或其他语言编写,本地方法也不由JVM去运行,所以本地方法的运行不受JVM管理。
- HotSpot VM将本地方法栈和JVM栈合并了。
- 本地方法栈也会在深度溢出或扩展失败的时候,分别抛出StackOverflowError 和 OutOfMemoryError 异常。
三、垃圾回收机制
程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。GC是不定时去堆内存中清理不可达对象。