1. 代码编译:Java程序被编译成Java字节码。(这是jdk完成的,不是jvm)
2.类加载(jvm类装载器):JVM将Java字节码文件加载到内存,并对其进行解析和验证。如果字节码文件有语法错误,则JVM会拒绝载入并输出错误信息。
3. 执行:JVM对Java字节码进行解释运行(解释器执行方式)或JIT(Just In Time,即时编译器)编译为本地代码后再执行,具体采用哪种方式取决于虚拟机的实现。
1.使用Java -version命令可以看出当前虚拟机处于哪种模式。(64位系统只支持Server模式)
2.JIT是将热点代码编译为机器码,如何判断是否为热点代码,当是server模式的时候10000次开始每次执行后-1,为0后判定为热点代码,当是client模式的时候1500此开始执行-1,为0后判定为热点代码
server模式:启动慢,属于重量级,运行后执行速度快很多,因为经过全局优化,编译后的代码质量很高
client模式:启动快,运行效率低,因为只做局部代码优化
4.内存管理:JVM负责管理Java程序执行过程中所使用的内存,包括heap、stack、非RAM的内存区域等。
5. 垃圾回收:Java虚拟机还提供自动垃圾回收的机制,定时回收不再使用的对象并释放内存。
6. 反射:Java程序可以在运行时获取自己的类信息并对其进行操作,这就需要Java虚拟机提供反射的机制。
jvm内存管理(重点)
1.元空间(方法区):jdk1.7之前叫方法区,jdk1.8之后叫元空间,jdk1.7之前它被称为永久代,线程共享
存储数据:常量、常量池、静态变量(static)以及方法信息(修饰符、方法名、返回值、参数等)、类信息(类变量)等
jdk1.6前:永久代,常量池在方法区
jdk1.7:无永久代,常量池在堆中
jdk1.8后:无永久代,常量池在元空间
2.堆(线程共享)
存储数据:实例对象
堆分为两大块:老年代:新生代,内存占比2:1,新生代占整个堆空间1/3 ,老年代占整个堆空间2/3
新生代分为三个区域:新生区:幸存区from:幸存区to,内存占比8:1:1。
堆内存设置:
-Xmx(-X代表JVM参数设置,m代表Memory,x代表max最大):JVM最大内存
-Xms(-X代表JVM参数设置,m代表Memory,s代表start开始):启动初始内存
-Xmn(-x代表JVM参数设置,m代表Memory,n暂未想出来):新生代大小(包括了两个幸存区)
-Xss(-x代表JVM参数设置,s代表Stock,s代表start):每个线程虚拟机栈及堆栈的大小(可以解决StackOverFlowError问题)
1.幸存区to和和幸存区from并没有明确的规定名称,只要没有数据的那一方则为幸存区to
2.幸存区的存在是为了解决内存碎片的问题,其使用的是复制算法
3.新生区存满后,触发次收集(MinorGC),进行幸存区垃圾收集,将正在使用的对象用【复制算法】复制到另一个区域中,存活的年龄+1,新生代的对象默认生命周期超过 15 ,就会去养老区养老
4.老年代满了/调用System.gc()/元空间空间不足,触发全收集(full GC),使用【标记-清除】或【标记-整理】算法,GC后内存还不够则抛出OutOfMemoryError异常
3.栈(虚拟机栈-线程隔离)
又名堆栈,主管程序运行,生命周期和线程同步,线程结束,栈内存就释放了。不存在垃圾回收问题。
虚拟机栈储存的是:8大基本类型 + 对象引用 + 实例方法
1.内存溢出:StackOverFlowError
4.栈(本地方法栈-线程隔离)
本地方法栈储存的是:本地接口库里调用的方法,就是java里面native关键字修饰的方法。
凡是带native关键字的,说明java的作用范围达不到了,回去调用底层c/c++语言的库,首先会进入本地方法栈,然后到本地方法接口。
5.程序计数器(线程隔离)
每个线程启动是都会创建一个程序计数器,保存的是正在执行的jvm指令,程序计数器总是指向下一条将被执行指令的地址。生命周期与线程的生命周期保持一致。
jvm四种GC算法
1.引用计数算法(绑定对象)
每个对象在创建的时候,就给这个对象绑定一个计数器。每当有一个引用指向该对象时,计数器加一;每当有一个指向它的引用被删除时,计数器减一。这样,当没有引用指向该对象时,该对象死亡,计数器为0,这时就应该对这个对象进行垃圾回收操作。
2.标记–清除算法(老年代)
为每个对象存储一个标记位,记录对象的状态(活着或是死亡)。
分为两个阶段,一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。
3.标记–整理算法(老年代)
标记-整理法是标记-清除法的一个改进版。同样,在标记阶段,该算法也将所有对象标记为存活和死亡两种状态;不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间,然后把剩下的所有对象全部清除。这样就达到了标记-整理的目的。
4.复制算法(新生代的幸存区)
该算法将内存平均分成两部分,然后每次只使用其中的一部分,当这部分内存满的时候,将内存中所有存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内存,循环下去。
这个算法与标记-整理算法的区别在于,该算法不是在同一个区域复制,而是将所有存活的对象复制到另一个区域内。