JVM基础(持续更新)

JVM

Base on:https://www.bilibili.com/video/BV1yE411Z7AP?p=3&spm_id_from=pageDriver

1、引言

什么是JVM?

定义:Java Virtual Machine - java程序的运行环境(java二进制字节码的运行环境)

好处:

  • 一次编写,到处运行
  • 主动内存管理,垃圾回收功能
  • 数字下标越界检查
  • 多态

比较:

JVM、JRE、JDK

学习JVM有什么用?

  • 面试
  • 理解底层的实现原理
  • 中高级程序员的必备技能

常见的JVM

image-20220105191454160

学习路线

image-20220105191712863

2、内存结构

2.1 程序计数器

image-20220105191851406

2.1.1 定义

Program Counter Register 程序计数器(寄存器)

2.1.2 作用

作用:记住下一条jvm指令的执行地址

特点:

  • 是线程私有的
  • 不会存在内存溢出

image-20220105192402746

image-20220105192714960

2.2 虚拟机栈

2.2.1 定义

Java Virtual Machine Stacks(Java 虚拟机栈)

  • 每个线程运行时需要内存,称为虚拟机栈
  • 每个栈由多个栈帧(Frame)组成、对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着正在执行的那个方法

image-20220105193030424

演示
package com.caopeng.jvm.t1;

/**
 * @author Crescent_P
 * @date 2022-01-05 19:34
 */
public class Demo1_1 {
    
    
    public static void main(String[] args) {
    
    
        method1();
    }

    private static void method1() {
    
    
        method2(1,2);
    }

    private static int method2(int a, int b) {
    
    
        int c = a + b;
        return c;
    }
}

image-20220105193925850

问题辨析
  1. 垃圾回收是否涉及栈内存?

    答:不涉及,因为栈内存是一次次方法调用产生的栈帧内存、每次方法调用完之后,栈帧会被弹栈,会自动地被回收掉。

  2. 栈内存的分配越大越好吗?

    答:不是,因为物理内存是一定的,栈内存越大、线程数会变少。

  3. 方法内的局部变量是否线程安全?

    答:判断是否线程安全、就是看多个线程对这个变量是否共享。一个线程对应一个虚拟机栈、一个方法对应一个栈帧,那么方法内的局部变量是对于这个线程来说是私有的。

package com.caopeng.jvm.t1;

/**
 * @author Crescent_P
 * @date 2022-01-05 21:21
 * 局部变量的线程安全问题
 	如果方法内局部变量没有逃离方法的作用范围,那就是线程安全的
 	如果局部变量引用了对象,并逃离了方法的作用范围,需要考虑线程安全问题
 */
public class Demo1_3 {
    
    

    public static void main(String[] args) {
    
    
        StringBuilder sb = new StringBuilder();
        sb.append(4);
        sb.append(5);
        sb.append(6);
        // 创建一个新的进程
        new Thread(()->{
    
    
            m2(sb);
        }).start();
    }

    // 不存在线程安全问题
    public static void m1(){
    
    
        // 方法内的局部变量
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }

    // 存在线程安全问题
    // 作为参数,有可能有其它的线程访问到它
    public static void m2(StringBuilder sb){
    
    
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }

    // 不能
    // 会将sb返回,那么其它进程就可能拿到这个sb
    public static StringBuilder m3(){
    
    
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        return sb;
    }

}

2.2.2 栈内存溢出

栈帧过多导致栈内存溢出

image-20220105212953526

栈帧过大导致栈内存溢出

image-20220105213029073

演示
package com.caopeng.jvm.t1;

/**
 * @author Crescent_P
 * @date 2022-01-05 21:31
 * 显示栈内存溢出
 * -Xss256K
 */
public class Demo1_4 {
    
    
    private static int count;

    public static void main(String[] args) {
    
    
        try{
    
    
            method1();
        }catch(Throwable e){
    
    
            e.printStackTrace();
            System.out.println("count " + count); 	// count 34205
        }
    }

    // 没有终止条件,会一直递归调用
    private static void method1(){
    
    
        count++;
        method1();
    }
}

image-20220105213543006

package com.caopeng.jvm.t1.stack;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Arrays;
import java.util.List;

/**
 * @author Crescent_P
 * @date 2022-01-05 21:36
 *
 * json 数据转化
 */
public class Demo1_5 {
    
    
    public static void main(String[] args) throws JsonProcessingException {
    
    
        Dept d = new Dept();
        d.setName("Market");

        Emp e1 = new Emp();
        e1.setName("zhang");
        e1.setDept(d);

        Emp e2 = new Emp();
        e2.setName("li");
        e2.setDept(d);

        d.setEmps(Arrays.asList(e1,e2));

        ObjectMapper mapper = new ObjectMapper();
        // 将 部门类转化成json
        // 会一直递归,循环引用
        // { name : 'Market' , emps : [{ name : 'zhang' ,dept : { name: ''  ,emps : [}},]
        System.out.println(mapper.writeValueAsString(d));
    }
}

// 员工
class Emp{
    
    
    private String name;
    // 转化员工的时候,部门就不转化了
    @JsonIgnore
    private Dept dept;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Dept getDept() {
    
    
        return dept;
    }

    public void setDept(Dept dept) {
    
    
        this.dept = dept;
    }
}

// 部门
class Dept{
    
    
    private String name;
    private List<Emp> emps;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public List<Emp> getEmps() {
    
    
        return emps;
    }

    public void setEmps(List<Emp> emps) {
    
    
        this.emps = emps;
    }
}

image-20220105215225957

2.2.3 线程运行诊断

案例1:CPU占用过多

案例2:程序运行很长时间没有结果

2.3 本地方法栈

2.4 堆

2.5 方法区

猜你喜欢

转载自blog.csdn.net/Destiny_159/article/details/122333128