深入JVM之虚拟机栈

定义

Java Virtual Machine Sracks(Java 虚拟机栈)

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

注:

  1. 垃圾回收机制不涉及栈内存,因为栈内存在方法每次调用后被自动回收
  2. 栈内存分配不是越大越好
  3. 方法内的局部变量是否线程安全?
  • 如果方法内局部变量没有逃离方法的作用访问,它的线程就是安全的
  • 如果是局部变量引用了对象,并逃离方法的作用方法,需要考虑线程安全

栈内存溢出

栈帧过多导致栈内存溢出

示例代码:递归方法没有增加结束条件

public class demo {
    
    
    private static int count;
    public static void main(String[] args) {
    
    
        try {
    
    
            run1();
        }catch (Throwable throwable){
    
    
            throwable.printStackTrace();
            System.out.println(count);
        }
    }
    public static void run1(){
    
    
        count++;
        run1();
    }
}

在这里插入图片描述

栈帧过大导致栈内存溢出

示例代码:Json数据转换双向引用

import org.codehaus.jackson.map.ObjectMapper;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class demo2 {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //创建一个部门对象
        Dept dept = new Dept();
        dept.setDname("Market");
        //创建两个员工对象
        Emp emp1 = new Emp();
        Emp emp2 = new Emp();
        emp1.setEname("张三");
        emp1.setDname(dept);
        emp2.setEname("李四");
        emp2.setDname(dept);
        dept.setEmpList(Arrays.asList(emp1,emp2));
        System.out.println(new ObjectMapper().writeValueAsString(dept));
    }
}

class Emp {
    
    
    private String ename;
    private Dept dname;

    public Emp() {
    
    
    }

    public String getEname() {
    
    
        return ename;
    }

    public void setEname(String ename) {
    
    
        this.ename = ename;
    }

    public Dept getDname() {
    
    
        return dname;
    }

    public void setDname(Dept dname) {
    
    
        this.dname = dname;
    }

    public Emp(String ename, Dept dname) {
    
    
        this.ename = ename;
        this.dname = dname;
    }
}

class Dept{
    
    
    private String dname;
    private List<Emp> empList;

    public Dept() {
    
    
    }

    public String getDname() {
    
    
        return dname;
    }

    public void setDname(String dname) {
    
    
        this.dname = dname;
    }

    public List<Emp> getEmpList() {
    
    
        return empList;
    }

    public void setEmpList(List<Emp> empList) {
    
    
        this.empList = empList;
    }

    public Dept(String dname, List<Emp> empList) {
    
    
        this.dname = dname;
        this.empList = empList;
    }
}

在这里插入图片描述

线程运行诊断

案例1:cpu占用过多(在linux操作系统中进行)

/**
 * 演示 cpu 占用过高
 */
public class Demo1_16 {
    
    

    public static void main(String[] args) {
    
    
        new Thread(null, () -> {
    
    
            System.out.println("1...");
            while(true) {
    
    

            }
        }, "thread1").start();


        new Thread(null, () -> {
    
    
            System.out.println("2...");
            try {
    
    
                Thread.sleep(1000000L);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }, "thread2").start();

        new Thread(null, () -> {
    
    
            System.out.println("3...");
            try {
    
    
                Thread.sleep(1000000L);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }, "thread3").start();
    }
}

  1. 用top定位哪个进程对cpu的占用过高
  2. 再用ps命令进一步定位是哪个线程引起的cpu占用过高
    ps H -eo pid,tid,%cpu | grep 进程id
  3. 根据进程id列出该进程的所有线程:jstack 进程id
  4. 将找到线程的线程id换算成16进制,即可在列表中找到具体问题

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

package cn.itcast.jvm.t1.stack;

/**
 * 演示线程死锁
 */
class A{
    
    };
class B{
    
    };
public class Demo1_3 {
    
    
    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();
    }

}

猜你喜欢

转载自blog.csdn.net/zh2475855601/article/details/114583181