编写 .JAVA 文件 通过JAVAC 转换成 class文件 在通过虚拟机转换成电脑识别的文件
JVM整体划分
运行时数据区:堆 和 方法区 线程共有,其他线程私有。
类加载
加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象。
连接,连接又包含三块内容:验证、准备、初始化。
1)验证,文件格式、元数据、字节码、符号引用验证;
2)准备,为类的静态变量分配内存,并将其初始化为默认值;
3)解析,把类中的符号引用转换为直接引用
初始化,为类的静态变量赋予正确的初始值。
加载,双亲委派模型
当一个类收到类加载的请求,他不会首先加载这个类,而是将请求委派给父加载器去完成
自底向上寻找 在自顶向下 查找加载
自定义类加载:
继承ClassLoader 重写 findClass()方法
如何打破双亲委派模型:
重写 loadClass() 方法
JIT即使编辑器
就是把这些Java字节码重新编译优化,生成机器码,让CPU直接执行。这样编出来的代码效率会更高。
编译也是要花费时间的,我们一般对热点代码做编译,非热点代码直接解析就好了。
热点代码解释:一、多次调用的方法。二、多次执行的循环体
运行时数据区
PC程序计数器
存放指令 程序计数器指的是当前线程正在执行的字节码指令地址(行号)
ava中最小的执行单位是线程,因为虚拟机的是多线程的,每个线程是抢夺cpu时间片,程序计数器就是存储这些指令去做什么,比如循环,跳转,异常处理等等需要依赖它
每个线程都有属于自己的程序计数器,而且互不影响,独立存储。
虚拟机栈
一个方法 一个栈帧
里边包含 局部变量表,操作数栈,动态链接,返回地址
大致应该是这样的~~~ main 是一个栈帧 c1 是一个栈帧
局部变量表:是变量值的存储空间,由方法参数和方法内部定义的局部变量组成,
操作数栈:后入先出栈,由字节码指令往栈中存数据和取数据,栈中的任何一个元素都是可以任意的Java数据类型。
动态链接:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有该引用是为了支持方法调用过程中的动态连接。
返回地址:存放调用调用该方法的pc计数器的值。
本地方法栈
本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的
堆
Java中的堆是用来存储对象本身的以及数组(数组引用是存放在Java栈中的)。堆是被所有线程共享的,在JVM中只有一个堆。
方法区
方法区 1.8前 Perm Soace 1.8后 Meta Space
与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。
在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,
对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。
GC垃圾回收
什么是垃圾?
在 C语言申请内存 C++ new delete C/C++ 手动回收内存
java 自动回收内存
没有任何引用指向的一个对象或者多个对象(循环引用)
如何定位垃圾:
引用计数:看还有几个引用指向它
可达性分析 :简单来说 能到就不是垃圾 到不了就是 主要使用的是这种
常见垃圾回收算法:
标记清除 mark sweep :位置不连续 产生碎片 效率偏低(两遍扫描)
拷贝算法 copying:找出那些有用的,拷贝到另外一块内存去。 没有碎片,浪费空间
标记压缩 mark compact:有用的整理出来 扫描俩次,移动对象,效率偏低。 不会产生碎片,方便对象分配 不会产生内存减半。
分代垃圾回收算法:根据回收对象的特点进行选择,在jvm中,年轻代适合使用复制算法,老年代适合使用 标记清除或标记压缩算法。
JVM 内存分代模型
1:2 可以通过参数来改变。 survivor 幸存区 1.8前 永久代 1.8后元空间
MinorGC/YGC:年轻代空间耗尽时触发
MajorGC/FullGC:在老年代无法继续分配空间时触发,新生代老年代同时进行回收
一个对象的出生到消亡:
->eden区->survivor( S0)(经过一次垃圾回收)->survivor2 (S1)->年龄够了 老年代
对象何时进入老年代
超过指定次数(YGC) 不设置就是默认参数 15
常见垃圾回收器
他们吧大部分是可以相互组合使用的
Serial 单线程 Parallel 多线程 常见组合:(Serial+Serial Old)(Parallel Scavebge + Parallel Old) (ParNew + CMS)
Serial GC(串行收集器)应用特点:
1.内部只使用一个线程去回收(不能充分利用CPU的多核特性),无法并行化
2.GC过程可能会产生较长的时间停顿
Parallel Scavebge 年轻代 并行回收 与Serial 同理 但清理线程是多线程
ParNew 年轻代 配合CMS的并行回收
Concurrent Mark and Sweep (CMS) :老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间
G1 : 三色标记 + SATB
三色标记: 白灰黑 SATB :关注引用的删除
JVM参数配置
运行时 配置 Run-> Edit Config........
-Xmn -Xms -Xmx -Xss
年轻代 最小堆 最大堆 栈空间
-XX:+UseTLAB 使用TLAB,默认打开
-XX:+PrintTLAB 打印TLAB的使用情况
-XX:TLABSize 设置TLAB大小
-XX:+DisableExplictGC
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationConcurrentTime 打印应用程序时间
-XX:+PrintGCApplicationStoppedTime 打印暂停时长
-XX:+PrintReferenceGC
记录回收了多少种不同引用类型的引用
-verbose:class 类加载详细过程
-XX:+PrintVMOptions 打印JVM运行时参数
-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
-Xloggc:opt/log/gc.log gc日志
-XX:MaxTenuringThreshold
升代年龄,最大值15
这个参数 太多了~~~~
在运行中 可以使用 工具来排查 可视化工具 jvisualVm 在 jdk /bin 目录