JVM内存区域
在说明完类加载机制之后再说收jvm内部各个区域是如何工作的。
一、各个区域作用
1、mateSpace方法区
在jdk1.7之前(包含1.7)这块区域叫做永久代,在jdk1.8之后就没有永久代了,只有mateSpace(元数据区域),这个区域是存储初始加载类的描述信息。
2、程序计数器
首先需要明白我们写好的Java代码会被翻译成字节码,对应各种字节码指令,而当JVM初始化类信息之后就会执行字节码执行引擎,去执行编译出来的代码指令
,那么在执行字节码指令的时候,JVM就需要一个特殊的区域就是
程序计数器
,程序计数器就是用来记录当前执行的字节码指令的位置。值得一提的是程序计数器是每个线程独有
也就是程序执行的位置,那么为什么需要记录这个程序执行的位置呢?
Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,也就是说,在同一时刻一个处理器内核只会执行一条线程,处理器切换线程时并不会记录上一个线程执行到哪个位置,所以为了线程切换后依然能恢复到原位,每条线程都需要有各自独立的程序计数器。
3、java虚拟机栈
每当启动一个新线程时,Java虚拟机都会为它分配一个Java栈。Java栈以帧为单位保存线程的运行状态。虚拟机只会直接对Java栈执行两种操作:以帧为单位的压栈和出栈。
某个线程正在执行的方法被称为该线程的当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。在线程执行一个方法时,它会跟踪当前类和当前常量池。此外,当虚拟机遇到栈内操作指令时,它对当前帧内数据执行操作。
每当线程调用一个Java方法时,虚拟机都会在该线程的Java栈中压入一个新帧。而这个新帧自然就成为了当前帧。在执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等数据。
Java方法可以以两种方式完成。一种通过return返回的,称为正常返回;一种是通过抛出异常而异常终止的。不管以哪种方式返回,虚拟机都会将当前帧弹出Java栈然后释放掉,这样上一个方法的帧就成为当前帧了。
Java帧上的所有数据都是此线程私有的。任何线程都不能访问另一个线程的栈数据,因此我们不需要考虑多线程情况下栈数据的访问同步问题。当一个线程调用一个方法时,方法的的局部变量保存在调用线程Java栈的帧中。只有一个线程能总是访问那些局部变量,即调用方法的线程。
摘自博客:https://www.cnblogs.com/wade-luffy/p/5753057.html
4、java虚拟机堆
堆存放的就是实例对象。
5、核心区域串联
以下代码作为案例,来一步步解析jvm是如何执行这段代码的
public class Kafka {
public static void main(String[] args) {
ReplicaManager replicaManager = new ReplicaManager();
}
public static class ReplicaManager {
public void loadReplicasFromDisk() {
Boolean hasFinishedLoad = false;
if (isLocalDataCorrupt()) {
}
}
public Boolean isLocalDataCorrupt() {
Boolean isCorrupt = false;
return isCorrupt;
}
}
}
如下图所示:
二、各个区域配置命令
-Xms:Java堆内存的大小
-Xmx:Java堆内存的最大大小
-Xmn:Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小了 -
XX:PermSize:永久代大小
-XX:MaxPermSize:永久代最大大小
-Xss:每个线程的栈内存大小