JVM帮助我们进行了内存管理,写Java代码不像其它语言一样要释放内存等的内存管理操作,使得我们可以更加的关注业务。
1.jvm,jre,jdk几个的关系图解:
2.JVM运行时数据区:程序的各种变量运行时候的状态,是一个逻辑概念
其中,程序计数器,虚拟机栈,本地方法栈是线程独享,方法区和堆是线程共享的:
3.下面介绍虚拟机栈
它的单位是栈帧,一个方法一个栈帧,每个栈帧中又主要包含这几个主要的部分:局部变量表,操作数栈,动态链接,出口等等,局部变量表和操作数栈是对方法中的变量的定义与计算,动态链接是解析方法执行,出口可以理解成是方法的返回。结合实际的例子来分析。编写一个Java代码:
package com.test.demo.mvc.action;
import java.io.File;
public class HelloWorldDemo {
//常量 静态变量
private final int i =0;
private static int k=0;
//成员变量
private Object obi = new Object();
private int sss =0;
public void methodOne(int i){
int j = 0;
int sum = i+j;
Object acb = obi;
long start = System.currentTimeMillis();//里面是本地方法
methodTwo();
return;
}
public void methodTwo(){
File file = new File("");
}
public static void methodThree(){methodThree();}
public static void main(String[] args) {
methodThree();
}
}
对编译生成的class文件(HelloWorldDemo.class)进行反编译
打开jp.txt,发现是看不懂的,可以通过javap指令集理解下面的指令:https://www.cnblogs.com/JsonShare/p/8798735.html
这里列出一部分:
iconst_0 将int类型常量0压入栈
istore_2 将int类型值存入局部变量2
iload_1 从局部变量1中装载int类型值
iload_2 从局部变量2中装载int类型值
iadd 执行int类型的加法
istore_3 将int类型值存入局部变量3
aload_0 从局部变量0中装载引用类型值
getfield 从对象中获取字段
astore 将将引用类型或returnAddress类型值存入局部变量
invokestatic 调用类(静态)方法
lstore 将long类型值存入局部变量
Compiled from "HelloWorldDemo.java"
public class com.test.demo.mvc.action.HelloWorldDemo {
public com.test.demo.mvc.action.HelloWorldDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_0
6: putfield #2 // Field i:I
9: aload_0
10: new #3 // class java/lang/Object
13: dup
14: invokespecial #1 // Method java/lang/Object."<init>":()V
17: putfield #4 // Field obi:Ljava/lang/Object;
20: aload_0
21: iconst_0
22: putfield #5 // Field sss:I
25: return
public void methodOne(int);
Code:
0: iconst_0
1: istore_2
2: iload_1
3: iload_2
4: iadd
5: istore_3
6: aload_0
7: getfield #4 // Field obi:Ljava/lang/Object;
10: astore 4
12: invokestatic #6 // Method java/lang/System.currentTimeMillis:()J
15: lstore 5
17: aload_0
18: invokevirtual #7 // Method methodTwo:()V
21: return
public void methodTwo();
Code:
0: new #8 // class java/io/File
3: dup
4: ldc #9 // String
6: invokespecial #10 // Method java/io/File."<init>":(Ljava/lang/String;)V
9: astore_1
10: return
public static void methodThree();
Code:
0: invokestatic #11 // Method methodThree:()V
3: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #11 // Method methodThree:()V
3: return
static {};
Code:
0: iconst_0
1: putstatic #12 // Field k:I
4: return
}
他们之间的剖析:
xss可以表示虚拟机栈的大小,每个方法的栈帧的大小是不一致的,因为他们的局部表量表与操作数栈的大小都是不一致的
4.JMM的介绍(Java Memory Model)
这个要根据jdk的版本进行区分,edn是伊甸区,s0,s1是survivor区
有三种GC(垃圾收集器)方案:MinorGC MajorGC FullGC
新生代触发的是MinorGC,老年代触发的是MajorGC,FullGC等价于MinorGC + MajorGC
什么样的对象会被GC?
引用不可达的对象将会被回收,从GC Root出发,关联不起来的对象都会被回收
有哪些常见的回收算法?
标记清除算法 复制算法 标记-整理算法
有哪些常见的垃圾回收器//收集器?
Serial ,ParNew ,Parallel Scavenge, Serial Old , Parallel Old,CMS,G1
可以通过jdk提供的工具jconsole观察内存情况:
思考问题:为什么edn:s0:s1是8:1:1?
希望Gc Root不可达的对象,在minor gc的时候能回收98%的对象,如果是使用其它的比例如9:1那么就会导致回收的比例降低,不会被回收的对象最后会启用担保机制,分配担保,分配到老年代,不希望对象最后进入到老年代,进入老年代要启用Major Cc来回收,会慢很多,8:1:1的好处就是可以触发多次的Minor GC,及时的干掉死掉的对象,至于为什么不是10:1:1这种,就是人家建议规定是这样的,自己可以根据自己的业务去调整是10:1:1