JVM02——虚拟机栈与本地方法栈

栈:线程运行时需要的内存空间,栈帧:每个方法运行时需要的内存。每个线程只能有一个活动栈帧,来对应当前正在执行的方法。

图片说明
使用idea可以调试获取虚拟机栈信息。

图片说明
垃圾回收不会涉及栈内存,因为栈的栈帧会随着方法调用而入栈,随着方法结束而出栈,无需进行垃圾回收。

栈的大小可以进行设置,线程栈越大则可以进行嵌套调用的方法层级越多,但是需要在合理区间,不是越大越好。因为计算机的物理内存是有限的,线程中栈的大小设置的越大,可以容纳的线程数就会越少(每个线程都有自己的栈)。

图片说明
局部变量是方法栈的私有变量,那么方法内的局部变量是不是一定是线程安全的呢?

  • 如果方法内的局部变量没有逃离方法的作用范围,则是安全的。

  • 如果是基本数据类型,则是安全的。

  • 如果是对象类型数据,并且逃离了方法的作用范围,则线程不安全。参考代码demo1,不同线程栈的变量中存放的地址不会彼此干扰,但同一地址的值可以被不同的线程所修改。

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

导致栈内存溢出的情况:

  • 入栈栈帧过多,如方法递归次数过多。
  • 栈帧过大,这种情况很少出现。

值得注意的是,有时候并不是我们自己写的代码导致了栈的内存溢出问题,而是错误使用第三方库的代码时导致了内存溢出问题。

cpu占用很多。

下面分析两个栈相关的案例。

  • cpu占用率过高

    在linux下可以使用top来显示cpu被进程占用的情况,定位到占用过高cpu的进程后,使用ps H -eo pid tid %cpu | grep xxx(进程id)来查看具体是哪个线程导致的问题。最后使用jstack xxx(进程id)查看进程所有线程对应的id及引起问题的源码行数。注意使用第二步得到线程编号是十进制,而jstack中的线程编号是16进制,需要进行必要的进制换算。

  • 线程迟迟得不到结果

    依旧使用jsatck定位问题,可以定位到类似下图的信息。

图片说明
本地方法是指非java语言编写的用于与操作系统底层功能交互的方法。本地方法栈用于给本地方法提供内存空间。

java全栈日日学 文章被收录于专栏

java全栈每日必学,不要高估自己一年能做的事,不要低估自己十年能做的事

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务