JVM基础篇-虚拟机栈

在这里插入图片描述

定义

Java Virtual Machine Stacks (Java 虚拟机栈)

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

栈帧组成部分:方法参数、局部变量、返回地址

执行流程

方法执行时执行压栈操作,如果该方法调用了其他方法,其他方法被调用时执行压栈操作,方法执行完成后执行出栈操作

在这里插入图片描述

问题辨析

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

答:不涉及,当方法执行完成后会执行出栈操作,对应的栈内存会被自动释放

栈内存分配越大越好吗?

答:不是,栈内存的越大只会使得方法递归调用的次数增大,但是如果栈内存越大,则意味着每个线程占用的内存越大,而可同时运行的线程数则会变少

📌指定栈内存大小

-Xss:
  • 如果不设置,在Linux/MacOS中默认为1024KB,Windows系统则依赖于虚拟内存的大小

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

  • 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
  • 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全,如果方法参数或返回值为基本类型,则依然线程安全
package com.vmware.stack;

public class Demo1 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        new Thread(() -> {
            m2(sb);
        }).start();
    }

    /**
     * @apiNote 该方法中StringBuild线程安全,因为外部无法方法
     */
    public static void m1() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(1);
        stringBuilder.append(2);
        stringBuilder.append(3);
        System.out.println(stringBuilder.toString());
    }

    /**
     * @param builder
     * @apiNote 该方法线程不安全,因为StringBuild可能有其他线程访问
     */
    public static void m2(StringBuilder builder) {
        builder.append(1);
        builder.append(2);
        builder.append(3);
        System.out.println(builder.toString());
    }

    /**
     * @apiNote 该方法线程不安全,可能有其他线程访问返回值进行修改
     * @return
     */
    public static StringBuilder m3() {
        StringBuilder builder = new StringBuilder();
        builder.append(1);
        builder.append(2);
        builder.append(3);
        return builder;
    }
}
栈内存溢出
  • 栈帧过多导致栈内存溢出
    • 方法递归调用
    • 部分第三方类库溢出,例如json序列化循环依赖
  • 栈帧过大导致栈内存溢出
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐