Jvm的基础知识
学习链接有艾编程的视频链接:https://www.icodingedu.com/course/26
学习链接有:https://ke.qq.com/course/230866?taid=3625454909228498
1.Window版本和linux版本的jdk会把对应的.class编译文件翻译为系统能识别的机器码。
Java的跨平台主要是靠java的虚拟机来实现的。
2.Java虚拟机的组成如下图:
分别由类装载器、运行时数据区、执行引擎组成jvm。
在程序运行时,jvm会分配内存(运行时数据区),开辟堆、和栈等。
在多个线程时,为不同的线程在栈内存里开辟不同的栈空间。如下图所示:
堆:一般情况下放新生成对象,如new Object()。
栈:存储每个线程的局部变量。
在线程执行不同方法的时候,jvm会在栈空间里为不同方法分配空间,用来存储不同方法的变量,即:栈帧。也就是一个方法对应一块栈帧内存区域。先进后出(FILO)。
对java的class文件使用javap -c Math.class > Math.txt进行反编译并输出到Math.txt文件中,根据程序执行顺序,先分配一个main()的栈区域,而后为computer()分配区域,computer()执行完成后,出栈,紧接着main()再出栈。也就是数据结构中的先进后出。
程序计数器:每一个线程都有自己的计数器,即程序即将执行的下一行代码的指针地址。当某一个线程挂起,再次恢复的时候,知道继续执行哪一行的代码就是通过程序计数器记录的。
操作数栈:在程序运行过程中的操作数的临时的中转内存。也是用的先进后出的栈来存储的。
方法出口:存放的是即将要执行的方法的程序计数器的值。
栈里面会有很多的局部变量存储的是堆内存里面的内存地址,指向堆里面的对象。
方法区(元空间)主要存放的是常量、静态变量、类元信息。元空间中的静态变量指向的堆内存的对象。
一个完整的对象由下图组成:
分别是:对象头 、实例数据、对齐填充。
其中对象头包括了1.GC分代年龄、哈希值、锁状态标志、线程持有锁等,2.Klass POinter(类型指针)3.数组长度(只有数组对象才有)
方法区(元空间)如Math.class被类装载系统加载到方法区,实际上就是方法区的类元信息。堆里面的通过new Math()创建出来的math和math2对象都指向了方法区的类元信息,即对象头的类型指针。
本地方法栈就是标志着native关键字的方法,本地方法其实就是跨语言调用,会去底层的代码去实现与系统的交互。现在用本地方法特别少。在每个线程执行过程中如果有用到本地方法的话,则jvm在内存中开辟一块本地方法栈的空间。如下图:
jvm在做gc收集时怎么判断堆里面的对象是垃圾对象呢?
答:将“GC Roots”对象作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未找到的对象都是垃圾对象。
“GC Roots”根节点:线程栈的本地变量、方法区中的静态变量、本地方法栈的变量等。
3.垃圾收集机制
堆空间分为:年轻代和老年代,年轻代又分为伊甸园区和survivor区。From区也叫作s0区,To区也叫作s1区。老年代默认占堆内存的2/3的空间,年轻代默认占1/3的空间。
当一个对象在堆里面的伊甸园(Eden)区,当伊甸园区放满后,经过第一次minor gc回收后,如果对象还存在引用,则会将该对象放到Survivor区的From区,并且Gc分代年龄会加1,GC的分代年龄存在该对象的对象头里。如上图所示。
第一次minor gc时,From区和To区都为空,随着程序不断运行,伊甸园区的对象第二次满了后,第二次minor gc回收会将伊甸园区和From区使用的对象分别加1放到To区,如下图:
随着程序不断运行,伊甸园区的对象第3次满了后,第3次minor gc回收会清理伊甸园区和To区,会将,伊甸园区和To区(复制算法)的对象分别加1放到To区,如下图:
当分代年龄=15时会被挪到老年代。如系统的静态变量,spring容器的bean对象会被挪到老年代,当老年代放满了后,也会做Gc,名称叫Full GC。
当老年代在进行FullGc后,还是满的就会出现out of Memery异常。内存溢出。
JDK自带jvisualvm监控工具
在cmd命令行输入jvisualvm命令即可出现。
minor gc和Full GC的区别?
答:minor gc会回收年轻代,Full GC会回收年轻代和老年代。
4.Jvm调优
1.让Full Gc的次数少一点。
2.让STW(stop the world)的时间短一点。
Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于gc引起。
亿级流量电商从在进行gc的时候,当前那一秒产生的对象不会清理,应该是要放到Survivor区的S0区,但因为60M超过了S0区空间的50%,因此会被直接挪到老年代。具体看下图1.4的对象动态年龄判断。
根据上面分析的判断,每13秒就会往老年代放60M的对象,那几分钟后就会进行Full Gc,那就会出现卡顿现象。
问题:能否进行jvm的参数调优?让系统几乎不卡顿?尽量减少full gc的次数。
答:老年代默认占堆内存的2/3的空间,年轻代默认占1/3的空间。为了解决卡顿的问题可以把年轻代的内存空间设置的大一些。如下图:
性能调优分为1.jvm调优,2.mysql调优,3.tomcat调优,4.nginx调优