什么是JVM?
JVM就是java虚拟机的缩写。Java语言一大特性就是平台无关性,jvm就是实现这一特性的关键。java文件被编译成 字节码文件(class文件)之后,然后jvm会执行字节码文件成为机器指令。所以java中有write once Run everywhere
的说法。
JDK、JRE、JVM关系图
JVM运行时数据区
我们知道java中最小的执行单位是线程,每个线程都有一套独立的程序计数器,虚拟机栈和本地方法栈,是线程安全的。不同的线程共享方法区和Heap。
程序计数器:指向当前线程正在执行的字节码指令的地址(行号)。
虚拟机栈:存储当前线程运行方法时所需要的数据,指令,返回地址。
虚拟机栈中存放的一个方法对应一个栈帧,包括了局部变量表,操作数栈,动态链接,出口等。线程的执行是栈顶的先执行。
栈帧是否是一样大小呢?
栈帧表示程序的函数调用记录,而栈帧又是记录在栈上面,很明显栈上保持了N个栈帧的实体,那就可以说栈帧将栈分割成了N个记录块,但是这些记录块大小不是固定的,因为栈帧不仅保存诸如:函数入参、出参、返回地址和上一个栈帧的栈底指针等信息,还保存了函数内部的自动变量,因此,不是所有的栈帧的大小都相同。
方法区:存储类信息,常量(JDK1.7+发生变化),静态变量,JIT等。
Heap:在jdk1.8之前的版本,我们通常把堆分为新生代,老年代和永久代(方法区)(我们通常认为方法区也是属于堆的),新生代又包含了eden,from和to(survivor),当对象存活了超过两个survivor的时候(在To里面通常由个年龄阈值作为晋升判断)会被转移到老年代中,这时候这个对象的数据就会存储在方法区内(GC在方法区的收益甚微),当这边的内存不够时就会报OutOfMemoryError:PermGen,这时候就可能会发生内存泄露问题。为了解决这个问题,jdk1.8完全把存放元数据的永久内存从堆内存转到了本地内存。