深入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();
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据老人家i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值