JVM是程序员的内功
为什么这么说呢?
我们可以回忆下第一天学习java的时候,我们的老师就和我们阐述一个问题
java为什么会火起来?java为什么能够跨平台,java的性能为什么这么高?jvm为什么
不需要内存管理,为什么它能够自己实现内存管理,它实现内存管理机制又是什么样的?
这些的问题就能够在jvm中找到答案
三、JVM内存模型
1、java语言为什么优势巨大,一处编译到处运行
很多的大型政府项目,金融项目,银行项目,包括互联网的高并发,高可用的项目都是用java语言实现的,那么为什么java语言这么受欢迎?在java语言出现的时候,像c,c++,.net这样的语言也经历过大型项目的验证,他们也是稳定的语言,但是像c,c++有缺陷:不能一处编译随处运行的,而主要运行在linux,unix上面,依赖linux,unix上面的文件库,而.net主要运行在windows上面?那么java为什么能够做到一处编译,多处运行?因为java有自动的内存的管理机制?可以自动的提供内存的分配和释放,但是有可能出现内存泄漏和内存溢出的。
jvm运行试数据区分为5块:方法区,java虚拟机栈,本地方法栈 ,堆,程序计数器
程序计数器:主要用来记录字节指令的行号,比如将.java的代码编译成一个class文件
那么class文件在jvm执行的时候,需要一行一行的去执行,那么程序计数器做的就是这个事情。
java虚拟机栈:类似于类中的方法,在执行方法的时候,那么java虚拟机就创建了一个栈帧,那么对应的从入栈,到出栈,那么就是整个方法调用的过程。那么就是一个方法对应一个栈。
本地方法栈:java虚拟机在执行一些本地方法库,在调用本地方法库的时候,在进行cas的时候,就会调用本地方法库中的native方法,native方法就是在本地方法栈里面运行的。
方法区/元数据库空间:主要存储类的类信息,类变量,静态变量。这些就会存储到本地方法区里面。
堆:几乎数组,对象的创建都是在堆中生成的。
方法区,堆:存储在线程的内存共享区,而java虚拟机栈,本地方法栈,程序计数器时线程内独有的一块区域,生命周期和线程的生命周期是一样的。
四、JVM内存模型 -程序计数器
1、是什么?
①、程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。
我们有可能用多线程访问这个类里面的方法。那么运行时数据区,它是一块独立的内存,那么程序计数器是线程隔离的数据区,也就是每个线程它有自己独立的程序计数器,那么这块内存是在线程里面单独隔离开来的不同的维护自己的程序计数器
②、线程是一个独立的执行单元,是由cpu执行的
③、字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常 处理,线程恢复等基础功能都需要在这个计数器来完成。
为什么:我们为什么要用程序计数器
为了线程切换后能恢复到正确的执行的位置,每条线程都有一个独立的程序计数器,cpu切换用,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为"线程私有”的内存,还有java虚拟机栈,本地方法栈
特点:内存区域中唯一一个没有规定任何OutOMemoryError情况的区域:因为程序计数器不需要程序员去操作
五、JVM内存模型-java虚拟机栈讲解
①、是什么?
用于作用于方法执行的一块java内存区域,也就是从方法执行的时候,会创建一块内存区域:模拟一下方法的执行流程:后进先出,先进后出的执行效率。
②、为什么?
每个方法在执行的同时都会创建一个栈帧(Stack Framel),用于存储局部变量表,操作数栈(对对象引用的地址:比如说引用了某个对象),方法出口(return 的值)等信息,每一个方法从调用直至执行完成的过程
而且栈帧里面的变量会存储在局部变量表里面,除了存储局部变量表,还会存储操作数栈。
③、特点:
局部变量表存放了编译期可知的(就是数据类型所对应的大小)各种基本数据类型(boolean,byte,char,short,int,float,long,double)以及对象引用(reference类型 :存放运用的指针)。
如果线程请求的栈深度大于虚拟机所允许的深度,将判处StackOverFlowError异常
六、JVM内存模型-本地方法栈讲解
是什么?
用于作用域本地方法执行的一块java内存区域
什么是本地方法?
为什么?
与java虚拟机栈相同,每个方法在执行的同时都会创建一个栈帧(Stack Framel)用于储存局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法从调用直接执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈的过程。
特点?
Hotshot将java虚拟机栈和本地方法栈合二为一
①、本地方法栈与Java虚拟机栈发挥的作用是相当的类似,区别就是Java虚拟机栈存储的java方法然后会编译成字节码。而本地方法栈执行的是native中的方法,native方法是方法上的修饰符
②、native修饰的方法不能有方法体,native方法调用cpu里面原子指令的一个方法,就是调用java语言之外的语言,比如调用c,c++语言,用native修饰。
③、CAS:是一条CPU的原子指令,Java方法在执行的时候会调用cas,类似于数据库中乐观锁的概念:就是多个线程尝试cas的操作,只有一个线程能够更新成功,其他线程全部更新失败,然后会被线程挂起,直到前面的一个线程更新成功成功之后。