JVM
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/098a5868453565b0011278a33025f2ea.png)
JVM虚拟机一共有三大板块组成,类加载子系统、字节码执行引擎、JVM运行时数据区。本次主要说明JVM运行时数据区,也就是平时说的JVM内存模型
JVM内存模型
图中看出内存模型一共分为5大块,堆、方法区、栈、本地方法栈、程序计数器。他们被划分为一块一块的内存区域
JMV内存分配参数
-Xmn3072M 代表堆初始化内存3个G。不设置话默认是物理内存的1/64
-Xms3072M 代表堆最大内存为3个G。不设置话默认是物理内存的1/4
-Xss512K 代表每个线程栈的最大使用内存
-XX:MaxMetaSpaceSize=256M 代表方法区最大内存为256MB
-XX:MetaSpaceSize=256M 代表方法区触发FULLGC的阈值,不设置话默认是21MB,达到该阈值后就会触发FULLGC,触发之后JVM会调整
该值,如果释放的空间多则会降低阈值,释放的少则会判断-XX:MaxMetaSpaceSize的值(-1情况下不判断),然后适当提高阈值。
-XX:+DisableExplicitGC 启动加上这个参数,程序中执行System.gc()就无效果,避免有人乱搞。 建议启用
堆
平时我们程序运行时产生的对象, 比如 new User() 这个对象实际就放在我们的堆中。堆中分配两大块一块年轻代用于存放我们新产生的对象。
一块老年代。用于存放我们长久使用的对象。具体各个区域的情况,请参考下一章,垃圾收集器与调优。**默认情况下**老年代占整个堆的三分之
二。年轻代占3分之一。年轻代中eden与s区域比例 8:1:1。
![堆内存分配图](https://i-blog.csdnimg.cn/blog_migrate/f319fc7c7e65ac7dca9ff0ac8222e8b0.png)
年轻代
eden 区
程序运行时产生的对象首先放到这里面,当eden区存放满了之后会执行minor gc也叫young gc 会回收eden区域所有垃圾对象。当回收完毕后
还存活的对象,则会放入s0区域(首次)
s0 s1 (Survivor区域 也叫存活区)
当eden进行垃圾回收时存活的对象会放在s0或者s1中。具体存放在哪儿取决于垃圾回收区域,如果这次垃圾回收收的s0则会放s1反之则放s0,
每次回收后还存活的数据则该数据的分代年龄会+1。
老年代
储存长久存活的对象。如s区域中进行gc时,分代年龄达到15的会挪到老年代中存放。或者当年轻代做gc时eden挪到s区域的对象大小大于s0或者
s1区域大小的50%,这种则会被直接挪到老年代。
方法区
储存我们程序中的常量、静态变量、类信息。存的这些信息其实是指向我们堆里面具体对象内存地址
本地方法栈
这个方法栈我们基本不会用到,是属于jdk自身带有native关键字的方法调用时锁产生的对象就会放到这个内存区域内
本地方法
比如我们要启动一个线程 thread.start()。实际上这个是我们java去调用jdk的Thread.java类中 start0() 方法,然后start0()方法是
通过jvm的c++源码程序调用服务器的cpu才开始一个线程;而start0();这种带有native关键字的方法就被称为本地方法。
private native void start0();
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b8121f3921cc2edaaa7c6560f65063e6.png)
程序计数器
记录我们每个线程线程执行到某一行代码的内存地址。
栈
每个线程运行的时候都需要一定内存,所以每个线程运行的时候JVM会给它分配一个独有的栈内存空间,放在这个栈中。存放线程中的局部变量。
每个线程不光能分配独立的栈内存空间,也能分配到一个独有的本地方法栈和程序计数器。有一个线程就会有它独有的栈、本地方法栈、程序计
数器。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/89c1e0bfd3a44615cd08fb573b1293d7.png)
栈帧
在线程的栈内存空间中,该线程每调用一个方法就会产生一个栈帧内存空间。每个栈帧里面会有上图所示的元素。
局部变量表
存放当前方法的局部变量
操作数栈(FILO)
用于当前方法数据计算的临时储存区,操作数栈中计算的数据通常来自于我们JVM的方法区。它一般通过弹栈/压栈来进行方法,操作数栈的具体
的指令可以通过将java类编译成可读性较高的字节码文件后对方法的指令进行解析。javap -c XXX.class > xxx.txt 可以将编译后的内容
放到指定txt文件中。 至于其中的具体指令去百度查一下JVM指令手册。
动态链接
将方法中的符号引用转变成直接引用。比如:方法中 main方法中 有一行代码 test.test();。刚解析main方法的时候并不会解析test的
test()方法。只会把test()方法当成一个符号(也叫符号引用)。当真正要执行它的时候才会解析test()方法。将test()符号解析成具体
test()方法的内存地址(变成直接引用)。这就是动态链接
方法出口
参考上图。方法1调用方法2的时候。方法2的方法出口存放的就是当自己执行完毕之后会回到哪个方法中,方法中的什么位置。方法出口里面就储存这些。