JVM
下图是JDK的结构图(来源于网络)
不同版本JDK的JRE是不同的,JVM会将相同的字节码文件解析成不同系统识别的0 1 二进制
JVM 的结构:
由以下代码引入:
public class Demo {
public static final double PI = 3.14;
static Circle circle = new Circle();
public static void main(String[] args) {
Demo demo = new Demo();
int c = demo.calculate();
System.out.println(c);
}
public static int calculate() {
int a = 2;
int b = 3;
int c = (a + b) * 2;
return c;
}
}
class Circle{
private double radius;
public Circle() {
this(1.0);
}
public Circle(double radius){
this.radius=radius;
}
}
为更加好理解栈帧,我们可以通过命令行查看Demo 的字节码文件:
javap -c Demo.class > Demo.txt//-c 为反汇编,可将字节码文件编译成更加容易理解的文件,并写入到 Demo.txt文件中
Compiled from "Demo.java"
public class Demo {
public static final double PI;
static Circle circle;
public Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class Demo
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: aload_1
9: pop
10: invokestatic #4 // Method calculate:()I
13: istore_2
14: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
21: return
public static int calculate();
Code:
0: iconst_2
1: istore_0
2: iconst_3
3: istore_1
4: iload_0
5: iload_1
6: iadd
7: iconst_2
8: imul
9: istore_2
10: iload_2
11: ireturn
static {};
Code:
0: new #7 // class Circle
3: dup
4: invokespecial #8 // Method Circle."<init>":()V
7: putstatic #9 // Field circle:LCircle;
10: return
}
JVM指令手册可以私聊我发给你们(免费)
堆的结构:
说明:分代的原因在于提高对象分配内存和垃圾回收的效率,新的对象会放在伊甸园区,当伊甸园区满了之后会由执行引擎进行垃圾回收,即young GC或称minor GC,存活的对象放入S1中,当伊甸园区再次满的时候会再次进行minor GC,这次收集的是伊甸园区和S1中的垃圾,将两个区中都存活的对象再放入S2中,而原先在S1中的对象的分代年龄+1,当伊甸园区再次满的时候再将伊甸园区和S2中存活的对象放入S1中,原先在S2中的对象的分代年龄+1;当一个对象的分代年龄到达15的时候,会被放入老年代,当老年代放满的时候会执行full GC,系统消耗非常高,应尽量避免full GC,一天、一周、一个月进行一次为正常,还有很多规则使对象直接进入老年代,例如其中之一:当Eden中存活的对象大小大于S1的50%时,就直接进入老年代。
JVM调优基础
当输入java -version时
会出现client或者server两种不同的机制,client机制更多的基于桌面级应用,分配的空间相对比server 少,但是server机制会造成空间浪费,这两种机制可以在jre中修改。
可以进行JVM调优的点:
- 选择client还是server机制
- 对堆的大小的分配,手动调参数
例如:-Xms:初始化堆的大小
-Xmx:最大堆大小
-XX:New Size:n:设置年轻代的大小 - 垃圾收集器的选择
JVM中的垃圾收集器:
连线表示收集器可以配合使用
serial收集器:唯一一个次收集器,是一个串行收集器,STW(stop the world):收集时暂停整个线程。(图片来自网络)
注意
新生代使用的是复制算法,而老年代使用的是标记-整理算法
parNew收集器:并行收集器,是CMS默认配合的收集器,多核CPU可以显示出能力,单核和serial效果一样。(图片来自网络)
parallel :提高吞吐率
系统吞吐率=代码执行时间/(代码执行时间+垃圾收集时间)
CMS收集器:垃圾收集和用户线程并发执行
G1:新生代和老年代的垃圾都可以回收
常用的垃圾回收算法
1.引用计数:
一个对象有一个引用就加1,少一个引用就减1,如果为0就回收,缺点是无法解决循环引用的问题
2.复制算法:
划分为两个相等的区域,只复制正在处理的对象,复制过去可以有序的整理,没有空间碎片,缺点:需要两倍空间
3.标记-清除算法:
第一阶段从引用的根节点开始标记所有被引用的对象,第二阶段遍历整个堆,将为标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。
4.标记-整理算法:
此算法是对标记-清除的优化,使用标记-清除方法清除后,再将存活的对象压入到堆中的一块区域,按顺序排好,解决了标记-清除的内存碎片问题和赋值的空间问题。
以上是自己对JVM所学整理的笔记,不完整,今后会逐步完善!
加油!