• Java中的虚拟机栈


    一. 定义

    JVM Stacks 虚拟机栈先进后出,后进先出

    二. 概述

    在这里插入图片描述

    • 每个方法在运行时需要的内存都会创建一个栈帧(Stack Frame)
      用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程

    • 栈帧( Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接(Dynamic Linking)方法返回值异常分派( Dispatch Exception)栈帧随着方法调用而创建,随着方法结束而销毁— —无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束

    注意:

    1. 线程私有,每个线程都会有Java虚拟机栈
    2. 每个线程运行时所需要的内存空间,称为虚拟机栈
    3. 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
    4. 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

    三. 栈的演示

    在这里插入图片描述

    四. 问题辨析

    1. 垃圾回收是否涉及栈内存?

      • 不需要,因为栈内存就是一次次方法调用所产生的栈帧内存,而栈帧内存在每一次方法调用结束后,都会弹出栈,自动的被回收掉,根本不需要垃圾回收来管理栈内存。
    2. 栈内存分配越大越好吗?

      • 栈内存划分越大,会导致线程数变少,例如一个线程需要1MB栈内存,100MB内存就能划分100个线程,但是如果一个线程需要2MB栈内存,那么100MB内存只能划分50个线程
    3. 方法内的局部变量是否是线程安全?

      • 如果方法内局部变量没有逃离方法的作用范围,他就是线程安全的
      • 如果局部变量引用了对象,并逃离方法的作用范围
      • 在这里插入图片描述

    五. 栈内存溢出

    1. 栈帧过多会导致栈内存溢出

    在这里插入图片描述

    1. 栈帧过大导致栈内存溢出

    在这里插入图片描述
    在这里插入图片描述

    代码演示

    /*
        演示栈内存溢出 StackOverflowError
        -Xss256k
     */
    public class Demo2 {
        private static int count;
    
        public static void main(String[] args) {
            try {
                method1();
            } catch (Throwable e) {
                e.printStackTrace();
                System.out.println(count);
            }
    
        }
        private static void method1() {
            count++;
            method1();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1. json数据转换也会出现

    注意:@JsonIgnore注解,假如把员工json化时,遇到部门属性直接略过不转该属性

    import java.util.Arrays;
    import java.util.List;
    
    /*
        json 数据转换
     */
    public class Demo2 {
        public static void main(String[] args) throws JsonprocessingException {
            Dept d=new Dept();
            d.setName("鸡你太美");
    
            Emp e1=new Emp();
            e1.setName("菜徐琨");
            e1.setDept(d);
    
            Emp e2=new Emp();
            e2.setName("小黑子");
            e2.setDept(d);
    
            d.setEmps(Arrays.asList(e1, e2));
            
            ObjectMapper mapper=new ObjectMapper();
            System.out.println(mapper.writeValueAsString(d));
        }
    }
    class Emp{
        private String name;
        private Dept dept;
    
        public Emp() {
        }
    
        public Emp(String name, Dept dept) {
            this.name = name;
            this.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 Dept() {
        }
    
        public Dept(String name, List<Emp> emps) {
            this.name = name;
            this.emps = 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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    六. 线程运行诊断

    • 案例1:CPU占用过多

    这里需要安装:

    1. VMware Workstation Pro
    2. Xshell 7(免费)
    3. SecureCRT.exe
      在这里插入图片描述
    1. 定位
      在这里插入图片描述

    2. 用top定位哪个进程对cpu的占用过高
      在这里插入图片描述

    3. ps H -eo pid,tid,%cpu | grep 进程id (用ps命令进一步定位是哪个线程引起的cpu占用过高)
      在这里插入图片描述

    4. jstack 进程id
      可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号
      在这里插入图片描述

      • 所以java:8,在源程序第8行出现问题
        在这里插入图片描述
    public class Demo2 {
        public static void main(String[] args) {
    //        Thread​(ThreadGroup group, Runnable target, String name) 分配一个新的 Thread对象,使其具有 target作为其运行对象,具有指定的 name作为其名称,属于 group引用的线程组。
            new Thread(null,()->{
                System.out.println("1...");
                while(true) {
    
                }},"菜徐琨01").start();
    
            new Thread(null,()->{
                System.out.println("2...");
                try {
                    Thread.sleep(1000000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"菜徐琨02").start();
    
            new Thread(null,()->{
                System.out.println("3...");
                try {
                    Thread.sleep(1000000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                },"菜徐琨03").start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 案例2:程序运行很长时间没有结果
    1. 输入nohup 路径 &进行连接
      在这里插入图片描述
    2. jstack 进程id
      可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号
      在这里插入图片描述
      • 原因:
        在这里插入图片描述
    class A extends Thread {
    }
    
    class B extends Thread {
    }
    
    public class Demo3 {
        static A a = new A();
        static B b = new B();
    
        public static void main(String[] args) throws InterruptedException {
            new Thread(() -> {
                synchronized (a) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (b) {
                        System.out.println("我获得了a和b");
                    }
                }
            }).start();
            Thread.sleep(1000);
            new Thread(() -> {
                synchronized (b) {
                    synchronized (a) {
                        System.out.println("我获得了a和b");
                    }
                }
            }).start();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    『 Linux | 1 』VMware上安装Ubuntu22.04
    在{{}}中拼接字符
    HarmonyOS4.0系统性深入开发38Web组件概述
    ToDoList使用自定义事件传值
    java计算机毕业设计网上购物商城演示录像源码+系统+数据库+lw文档+mybatis+运行部署
    C++类模板的重载
    Java中去掉字符串中的非中文字符
    力扣刷题day26|332重新安排行程、51.N皇后、37解数独
    .net 7 隐藏swagger的api
    Ceph块存储的安装部署和使用
  • 原文地址:https://blog.csdn.net/o676448/article/details/126314556