JVM (三) 详细学习jvm
此文针对B栈Monkey课程所做笔记,个人认为讲的真心不错,https://www.bilibili.com/video/av94156750?p=1
一、什么是JVM
熟悉jvm首先了解java体系,通过查看java代码相关编译运行,更好的了解jvm;从图中可以看出jvm底层是和操作系统打交道的
1、首先编写HelloWorld.java
public class HelloWorld {
// 类的属性:常量、变量、成员属性
private Object object = new Object();
private static int i = 0;
private static String s = "helloworld";
public int add () {
int a = 1;
int b = 2;
int c = (a + b) * 100;
return c;
}
public static void main(String[] args) {
HelloWorld app= new HelloWorld();
int result = app.add();
Thread.sleep(100);
System.out.println(result);
}
}
此处windows和linux分别下载对应机器的jvm,通过字节码达到在不同环境运行的目的,实现跨平台
二、JVM 底层原理
jvm 包括三部分,jvm运行时数据区、类加载子系统、执行引擎
此处说明一点,
本地方法栈,可以查看代码的Thread.sleep方法,为调用native方法的相关方法
方法区(元空间):为类的属性定义,对应直接内存,主内存
字节码class文件,需要通过java命令,才能到达类加载子系统;
cpu分配相应的时间调度,才能让执行引擎 根据 程序计数器的行号 执行相应的jvm相关方法
跟踪helloworld执行过程
main线程启动过程,需要在虚拟机栈、本地方法栈、程序计数器三部分分配空间
虚拟机栈针加载顺序
项目加载首先会加载main线程到虚拟机栈,然后加载add方法进入虚拟机栈
局部变量表:存储 int、short 、reference、long等数据类型
首先 执行引擎 根据iconst_1将1压入操作数栈,然后分局istore_1,将1赋值给局部变量表中的局部变量a=1,每次执行会根据程序计数器提供的行数进行执行指令,注意7-9之间有一个100,默认为8,执行乘法操作
通过javap -c HelloWorld.class 反编译字节码文件
通过javap -c HelloWorld.class > helloworld.txt 将相关的反编译代码输出到文件,相关操作可以查看jvm指令集
add方法将计算结果返回给main方法的局部变量表,局部变量表中的引用存在堆中,相应的类信息存在方法区中,其中类和引用的对应关系为一对多的关系
堆
内存默认占比:
堆分为新生代(1/3) 和 老年代(2/3)
新生代分为Eden (8/10) 、from(1/10) 、to(1/10)
为什么要进行性能调优?
主要也就是合理利用本来就不多的内存
内存回收的过程
步骤一:对象创建后默认放到新生代的Eden 区(詹姆斯高斯林为基督教徒),当Eden区内存占用满后,会调用一次 1minor young gc,并根据gc roots的可达性判断,根据对象是否被引用,决定是否清空Eden区
步骤二:然后标记对象的age = 1,并将Eden区清空,将正在使用的对象放到from 区,当from区满后,会调用第二次 2minor gc,并将age = 2
步骤三:将age = 2 的元素,通过复制算法,挪到to区,并将to改为from区,from改为to区,一直循环;直到第15次minor gc调用,将相关的对象移到老年代,默认不老不死,当老年代占用内存满后,就会提示内存不够,内存溢出OOM,并调用full gc,触发STW(网站停顿),整个系统处于不在运行状态
为什么采用分代回收的策略?
减少我们的stw 次数,其实就是减少full gc 次数,达到吞吐量、jvm调优
三、性能调优
demo实战
idea vm options 进行的参数配置
然后采用cms 垃圾收集算法:并发收集器,一般分为7步
初始化标记,并发标记
cms回收过程
cms优点:用户响应
缺点:会出现空间碎片
老年代垃圾清理:采用标记清理算法,将正在使用的标记压缩到一片区域,剩余的都是连续的可用的内存空间,其他不使用的就进行
还没有评论,来说两句吧...