1、jvm分为几部分?
jvm大体划分为三部分(1)类加载系统(2)数据内存模型(3)字节码引擎
2、jvm的作用:从宏观角度上理解,就是屏蔽了在代码在不同系统之间的差异,将字节码文件,转为了不同的机器码。
3、数据内存模型:
堆、栈、本地方法区、方法区(1.8版本后移到物理内存上了)、程序技术器
栈:被线程私有,即每一个线程都开辟一个栈。
同时栈内部分为(1)程序计数器(2)局部变量表(3)操作数栈
(4)动态链接(5)方法出口。
每一个栈其实都分配一个程序计数器,通过字节码引擎来动态技术,因为多线程的情况下,是抢占式。
其中字节码执行引擎的作用:
(1)程序计数器的变化
(2)加载方法区的字节码文件
(3)gc操作
4、jvm调优基础
可达性分析算法:从gcRoots开始引用查看对象,筛选出对象,并标记成非垃圾对象。
GC roots常见根节点:栈中的对象型局部变量,常量、本地方法栈变量。
堆中的内存模型
我们对堆内存模型,分为 年轻代——Eden区,survivor0,survivor1。年老代。
年轻代——Eden一般放置我们在程序运行过程中刚刚产生的对象。当我们的Eden
满了以后,会触发一次minorGC,将我们的非垃圾对象,移入到survivor区,survivor区使用的移动复制算法,并且在分代年龄上+1。
老年代:主要放置例如常量、bean对象、线程池对象,这种一直存活,以及在对象的对象头中分代年龄达到15次的对象。
我们常见的内存分配,3G总空间,老年代 2/3 ,Eden 8/10, survivor各1/10。
5、jvm的监控工具
cmd 命令jvisualvm 是一款jdk自带的监控jvm的工具,我们要想更明了的观察jvm各个区的变化,需要安装visual jvm 插件。
案例说明jvm调优:
我们电商网站一般在上亿级流量,日活大概500万的大网站上,我们就以我们的订单系统为例,当我们的集群在三天时,我们促销时单台大概在300/s个订单,这时我们以每个订单对象的大小在1kb左右,但不光只有我们的订单对象,其中可能包含促销、这款对象等,我们将其放到20倍即300*20——按照6M计算,如果我们考虑到系统的调用他方法例如查询等,我们将其再扩展10倍,即60M/s,也就是说我们在每秒产生60M的新对象放置在Eden但是我们也是在1s后将其列为垃圾对象。
那么问题可能出来了,我们的对象在minorGC时,会可能将最后1s的对象放置到survivor区,但是其大小只有100M超出了50%,我们虚拟机会将其放置到老年代。几分钟过去后就有可能将其站满触发fullGC。我们通常fullGC的触发在几天甚至几周触发一次。fullGC是影响性能的,造成用户会感觉到卡。
解决:就是将我们的年轻代的大小调整。可以调整到2G,就会避免这个问题。
此案例只是说明jvm调优的重要性,我们只是初窥jvm,其内容依旧博大精深。
心语:
自学的道路是孤独的,愿我们能够彼此共勉,希望能给你们带来一些帮助与启发。