Jvm内存模型与GC垃圾回收

1. 总览

在这里插入图片描述

程序计数器:

当前线程执行的字节码的行号指示器,通过改变此指示器来选取下一个需要执行的字节码指令。
特征:在线程创建时创建、每个线程拥有一个、指向下一条指令的地址

方法区:

jdk1.8之后叫元空间,1.8之前叫永久代。是线程共享的
存储:类信息、常量、静态变量、方法字节码

栈(线程)

是线程私有的,方法在执行时会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息
方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表所需的内存空间在编译期间完成分配,而且分配多大的局部变量空间是完全确定的,在方法运行期间不会改变其大小。出栈后空间释放。

是线程共享的,存储对象或数组。

本地方法栈:

存储本地方法(native)的局部变量

程序计数器、(线程)栈、本地方法栈都是每一个线程独有的(线程独享)。

2. 详细解释

示例程序:

package com.tuling.jvm;

public class Math {

    public static final int initData = 666;
    public static User user = new User();

    public int compute(){//一个方法对应一块站栈帧内存区域
        int a = 1;
        int b = 2;
        int c = (a + b)*10;
        return c;
    }

    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
        System.out.println("test");
    }
}

对class文件使用命令javap -c Math.class > Math.txt生成jvm指令码:在这里插入图片描述
部分指令解释:
iconst_1 -> 将int类型常量1压入操作数栈
istore_1 -> 在操作数栈中出栈(1),赋值给局部变量1

执行到4:iload_1,此时程序计数器的值就为4
iload_1 -> 会将局部变量1加载进操作数栈
iadd -> 会把操作数(1和2)出栈,执行相加操作,然后再把结果(3)三压入栈中
bipush 10 -> 把操作数(3)取出,与10做乘操作,再把结果(30)压入操作数栈中
在这里插入图片描述

局部变量表:存放局部变量
操作数栈:存放临时操作数
动态链接:将符号引用转换为直接引用
方法出口:记录上一个方法调用该方法时执行的位置信息,保证方法完成后能回到上一个方法的合适位置继续执行

方法区与堆:

1.方法区里面的静态类型变量如果有对象类型的,该变量是存储的堆中该对象的内存地址(Math中的user指向堆中的user对象)
2.在堆中,每一个对象的对象头里面都有一个class的类型指针指向方法区中的类元信息

在这里插入图片描述
我们new出来的对象一般都放在堆的Eden区中,默认配置中,老年代占堆内存的2/3,年轻代占1/3,年轻代中Eden占8/10,一旦Eden区中放满,会进行minor GC:

minor GC:垃圾收集——把无效的无引用的对象回收掉,把存活的或者有引用的对象放入From区,这些对象的分代年龄加1;
Eden区下一次被放满之后,又会触发minor GC,收集Eden,同时如果From区不为空,也会堆From区域进行回收,把存活下来的对象放入To区域,分代年龄加1;
再一次Eden区被放满之后,又会触发minor GC,对Eden、To区域做垃圾收集,把剩余存活的对象放入From区 ,分代年龄加1…反复运行,如果对象的分代年龄为15之后还没有被销毁,该对象会被移入老年代。

当老年代中放满之后,会进行full GC——对整个堆进行垃圾收集
在进行GC时,会进入STW

Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。

JVM性能调优就是要去减少GC的次数,减少GC的时间

垃圾收集结合实例:

package com.tuling.jvm;

import java.util.ArrayList;

public class HeapTest {

    byte[] a = new byte[1024*100]; //100KB

    public static void main(String[] args) throws InterruptedException {
        ArrayList<Object> heapTests = new ArrayList<>();
        while (true){
            heapTests.add(new HeapTest());
            Thread.sleep(10);
        }
    }
}

使用jdk自带的jvisualvm,安装visul GC插件,可以动态监视进程的情况:
在这里插入图片描述
文中原图链接:https://www.processon.com/view/link/5e82edb3e4b0412013f10583

本文是根据公开课学习整理的笔记…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章