目录
4.3 Java虚拟机栈:线程私有,描述Java方法的执行过程
JVM(Java Vritual Machine)是运行于Java字节码的虚拟机,包括一套字节码指令集、一组程序寄存器、一个虚拟机栈、一个虚拟机堆、一个方法区和一个垃圾回收器。JVM运行在操作系统之上,不与硬件设备直接交互。
Java源文件在通过编译器后被编译成相应的 .Class 文件(字节码文件),.Class 文件又被JVM中的解释器编译成机器码在不同的操作系统(Windows、Linux、Mac)上运行。每种操作系统的解释器是不同的,但基于解释器实现的虚拟机是相同的,这也是Java能够跨平台的原因。
通过 java.exe 程序,来运行 xxx.class,启动时就创建一个JVM

其中:
由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,因此在任何一个确定的时刻,一个处理器(多核处理器则指的是一个内核)都只会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各条线程之间计数器互不影响,独立存储。我们就把类似这类区域称之为"线程私有"的内存。
指存放数据的大小,超出该区域的内存大小。
运行时数据区域中,除了程序计数器,其他都可能发生OOM
在JVM运行过程中创建的对象和产生的数据都被存储在堆中,堆是被线程共享的内存空间,也是垃圾收集器进行垃圾回收的最主要的内存区域。由于现代JVN采用分代收集算法,因此Java堆从GC(Garbage Collection,垃圾回收)的角度还可以细分为:新生代、老年代和永久代。
堆的作用:程序中创建的所有对象都在保存在堆中(数组也是对象)
方法区的作用:用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据的。
在《Java虚拟机规范中》把此区域称之为“方法区”,而在 HotSpot 虚拟机的实现中,在 JDK 7 时此区域叫做永久代(PermGen),JDK 8 中叫做元空间(Metaspace)。
用于保存 局部变量表——变量(=左边的),基础数据类型的值(如果是基础数据类型,=右边的也在虚拟机栈)
Java 虚拟机栈的作用:Java 虚拟机栈的生命周期和线程相同,Java 虚拟机栈描述的是 Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。咱们常说的堆内存、栈内存中,栈内存指的就是虚拟机栈。
程序计数器是一块很小的内存空间,用于存储当前运行的线程所执行的字节码的行号指令器。
用于标识程序的行号
Java堆用于存储对象实例,只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免来GC清除这些对象,那么在对象数量达到最大堆容量后就会产生内存溢出异常。
内存泄漏 : 泄漏对象无法被GC。
内存溢出 : 内存对象确实还应该存活。此时要根据JVM堆参数与物理内存相比较检查是否还应该把JVM堆内存调大;或者检查对象的生命周期是否过长。
关于虚拟机栈会产生的两种异常:
内存泄漏:线程生命周期太长,导致始终只用一些不常使用的数据(这些数据gc无法正常回收),随着时间越来越长,最终导致OOM;
某个线程,调用方法,创建方法栈帧,入栈,如果栈中的栈帧超过jvm规定的数量,就会报这个异常。