jvm中的程序计数器、虚拟机栈和本地方法栈

news2024/11/16 10:31:42

引言

本文主要介绍一下jvm虚拟机中的程序计数器虚拟机栈本地方法栈


程序计数器

作用

作用:记录下一条jvm指令的执行地址。

下面具体描述一下程序计数器的作用。
在这里插入图片描述

这里有两个代码,右边的为源代码,左边为编译之后的字节码。

当我们直接写完源代码之后这个代码是不能直接交给CPU运行的,需要转化为对应的机器码才能让CPU运行。
具体的步骤:
源码 —> 字节码 —> 解释器 —> 机器码 —> CPU 运行。

在这整个过程中,程序计数器的作用就体现在字节码被解释器转化为机器码的过程中,在这个过程中,解释器每解释一条指令之后就会到程序计数器中取得下一次条指令的地址,然后程序计数器再指向下一条指令

除此之外程序计数器在多个线程运行中也起到关键的作用,接下来就顺便介绍一下程序计数器的特点,并探究一下在多线程中起到了什么作用。

特点

特点:
● 是线程私有的
● 不会存在内存溢出(唯一一个不会内存溢出)

这里具体介绍一下线程私有和程序计数器作用之间的关系,我们都知道CPU会给每个线程都分配时间片,当时间片用完之后线程就会停止运行被挂起了,所以在这个时候也需要记录一下接下来程序需要执行指令的地址,这正是程序计数器的作用。所以想要正确的保证时间片被用完之后还能记录程序运行的位置,为之后重新获得时间片继续执行程序,程序计数器是必不可少的。

同时我们也能发现为什么是线程私有的,因为每个线程都有自己所要执行的程序,并且需要分别记录自己程序将要执行位置,所以程序计数器是线程私有的,这样多个线程运行才不会乱套。


虚拟机栈

总结来说,虚拟机栈其实就是线程运行所需要的内存空间

虚拟机栈里存放的内容称为栈帧,而所谓的栈帧其实就是每个方法运行所需要的内存。里面包括方法的参数局部变量返回地址。所以每个方法执行时就需要提前将这些内存给分配好,然后每执行一个方法就会存放一个相对应的栈帧。
但是并不是虚拟机栈中只能存放一个栈帧,如果存在方法的嵌套的话,就会放入多个栈帧,并且是按照栈的数据结构进行保存的,当方法执行完之后再从栈中弹出。
虚拟机栈只能有一个活动栈帧,指的就是当前正在执行的方法。

栈的演示

这里就在写一个嵌套方法来演示栈。

public class Demo1 {
    public static void main(String[] args) {
        method1();
    }

    public static void method1(){
        method2(1, 2);
    }

    public static int method2(int a, int b){
        int c = a + b;
        return c;
    }
}

我们在main方法上打断点 debug 启动。
在这里插入图片描述

这里左边就是虚拟机栈里面存放着栈帧,右边就是这个栈帧的内容,这里面只有参数所以就显示了参数。当前的活动栈帧就是main方法。

当我们走到method1
在这里插入图片描述
这时活动栈帧就是method1方法,并且由于没有任何参数、局部变量和返回值所以就没有右边的栈帧内容。

接下来我们走到method2
在这里插入图片描述
这时我们的活动栈帧就是method2方法,并且也有栈帧内容。

当活动栈帧对应的方法走完之后,就会弹出这个栈帧。这里我们在点下一步就会把method2弹出,并且方法返回到method1
在这里插入图片描述
后续也是相同的。

问题辨析

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

这里其实并不会,因为栈帧内存其实在每一次方法之后就会自己弹出栈,然后就把内存释放掉了,所以不需要专门垃圾回收进行内存回收。

栈内存分配越大越好吗?

其实栈内容也并不是越大越好的,因为栈内存指的是当前线程运行所需要内容,而我们虚拟机分配的内存并不是无限大的,所以给栈分配的内存也不是无限的。而如果当我们栈的内存过大的话,就会导致我们能够创建的线程数就减少了,也可能会影响性能,所以并不是越打越好。

这里顺便介绍一个jvm的指令参数来设置栈内存大小。

-Xss size  // 后面跟一个大小
例如:
-Xss 1m
-Xss 1024k
-Xss 1048576

这个参数可以在idea中进行设置。
在这里插入图片描述
在这里插入图片描述

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

这里我们来观察一下代码

static void m1(){
    int x = 0;
    for (int i = 0; i < 5000; i++){
        x++;
    }
    System.out.println(x);
}

这个方法内的x其实是线程安全的,因为当我们有多个线程去调用这个方法时,那么就会创建多个对应m1方法的栈帧,然后在执行这个方法的时候每个线程都会创建自己单独的x局部变量,所以这个是安全的。
在这里插入图片描述

但是如果这个xstatic修饰的话,就不是线程安全的,因为这个变量就会被多个线程同时访问到,就会造成线程安全的问题。

在这里插入图片描述

接下来我们来看一下下面三个方法是不是线程安全的。

    public void method1(){
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }
    
    public void method2(StringBuilder sb){
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }
    
    public StringBuilder method3(){
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        return sb;
    }
    

首先看第一个,这个StringBuilder方法是一个局部变量,类似于上面的变量x所以这个是一个线程安全的,每个线程都会创建自己的StringBuilder

再看第二个,这个sb变量是通过参数传过来,这个就会有线程问题,可能调用者通过多线程来调用的这个方法,然后再主线程中同时对这个sb进行了操作,这样就会有问题。这时候就应该使用StringBuffer

类似于以下这种调用:

StringBuilder sb = new StringBuilder();
sb.append(1);
sb.append(2);
sb.append(3);
new Thread(() -> {
    method2(sb);
});

第三个同样有问题,当创建完之后的对象给返回出去了,那么别的线程拿到这个数据同样可能会进行多线程的操作造成了线程问题。

所以总结来说:
● 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
● 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

栈内存溢出:

造成内存溢出的原因具体有两种:
● 无限递归的方法调用没有返回,导致栈帧太多因此内存溢出
● 栈帧内存直接大于栈内存大小,导致内存溢出

由于第二种并不好实现,所以这里模拟一下第一种的情况。
具体代码:

    public static void main(String[] args) {
        method();
    }
    
    public static void method(){
        method();
    }
    

这时就会报一个StackOverflowError的错误就是栈内存溢出了。
在这里插入图片描述

线程诊断

cpu 占用高

这里写一个while(true)代码,然后再linux上进行运行。
接下来进行排查过程:

  1. 使用top命令查看资源占有情况
    在这里插入图片描述定位到 32655 进程资源占有高

  2. 查找相对应的线程
    这里使用ps命令可以查看线程的对cpu的使用情况。

ps H -eo pid,tid,%cpu

H:表示把当前进程下的所有线程都打印出来
-eo:表示后面添加的参数表示最后要展示哪些列,比如pidtid%cpu
在这里插入图片描述
还可以使用grep进行筛选

ps H -eo pid,tid,%cpu | grep 32655

可以查看到 32655 进程对应的 32665 的线程占有率很高。

  1. 查看所有线程
    使用 jdk 提供的工具 jstack 工具可以看查看当前进程中所有的线程。
jstack 32655

在这里插入图片描述

  1. 查找具体的线程
    查找通过ps命令找到的有问题的线程id(注意:这里需要将十六进制转化为十进制)
    32665 ==> 7f99
    在这里插入图片描述
    这里状态还是运行中,并且显示了有问题的代码行数。

程序运行很长时间没有结果

当我们启动完一个java程序之后没有给到相对应的返回结果时,命令行会返回一个当前启动的进程号。
然后通过这个进程号使用jstack命令来直接查询当前所有的线程
在这里插入图片描述

然后找到这个工具最后输出的内容:
如果有死锁导致没有输出结果的话,这里就会提示有死锁,并且提示有问题的代码行号。
在这里插入图片描述

总结:

定位:
● 使用 top命令查看哪个进程占用的cpu
● 使用ps H -eo pid,tid,%cpu | grep 进程id查看哪个线程占用cpu
jstack 进程id命令查看当前进程下的所有线程
○ 进一步查找有问题的线程,并定位到有问题的源码行数

本地方法栈

本地方法栈的作用就是给本地方法提供的一个内存空间,因为Java有些源码并不是用java写的,而是用c和c++写的本地方法(这是因为Java代码有一定的限制,不能直接跟操作系统底层打交道),所以为了能够调用这些本地方法,就专门有一个本地方法栈,专门用来调用这些方法供使用的。
具体有哪些本地方法,以Object类举例子:
像这种以native修饰的都是本地方法

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

#面试系列-腾讯后端一面

03.腾讯后端一面 项目相关 面试官可能是 Go 方向的&#xff0c;我面试的是 Java 方向的&#xff0c;所以面试官也没有问我简历上的项目&#xff0c;主要问了实验室中做的项目&#xff0c;哪个项目比较有技术挑战&#xff1f; 面试主要问了计算级网络相关&#xff0c;以及如果让…

企业应该怎样合理使用AI技术与混合云?

企业合理使用AI技术和混合云的关键在于明确业务目标、评估技术需求并制定相应的战略规划。下面是一些指导原则和步骤&#xff0c;可以帮助企业有效地结合AI技术和混合云&#xff1a; 1. 定义业务目标 明确需求&#xff1a;确定哪些业务流程可以通过AI优化&#xff0c;哪些数据处…

Python和R及MATLAB和C与Lua去相关生物医学图像处理和神经网络物理学及数学变换算法

&#x1f3af;要点 主成分分析降维显微镜成像精度评估算法脑电图磁共振成像降噪算法图像颜色分离显现特征球面转换:主成分分析和零相位分量分析零相位分量分析和主成分分析平均互相关算法图像白化计算噪声协方差和绘制白化数据高能物理分类器分离不同信号白化变换优化批量归一…

【贪心算法】贪心算法二

贪心算法二 1.最长递增子序列2.递增的三元子序列3.最长连续递增序列 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.最长递增子序列 题目链…

828华为云征文 | 使用Flexus X实例搭建Dubbo-Admin服务

一、Flexus X实例简介 华为云推出的Flexus云服务&#xff0c;作为专为中小企业及开发者设计的新一代云服务产品&#xff0c;以其开箱即用、体验卓越及高性价比而著称。其中的Flexus云服务器X实例&#xff0c;更是针对柔性算力需求量身打造&#xff0c;能够智能适应业务负载变化…

pick你的第一个人形机器人——青龙强化学习环境测试

文章目录 一、环境配置二、开始训练三、训练成果 最近感受到的大趋势是具身智能&#xff0c;强化学习&#xff0c;模仿学习做人形机器人&#xff0c;这个赛道很火&#xff0c;颇有前些年全力投入做自动驾驶的架势&#xff0c;正好最近用强化学习解决POMDP问题接触到了强化学习&…

Java研学-数据字典(一)

一 需求分析 1 分析 在项目中会有很多的下拉框&#xff0c;这些下拉框的特点&#xff0c;就是以键值对的形式存在&#xff0c;其中 value&#xff08;如 id&#xff1a;1&#xff0c;2… &#xff09;&#xff0c;key&#xff08;展示给用户的内容&#xff09;&#xff0c;数据…

SSC338D/SSC338Q CA7*2+IPU5M/Multi-sensorISP: HDR/3DNR

SSC338D/SSC338Q系列产品是高度集成的多媒体片上系统&#xff08;SoC&#xff09;产品&#xff0c;适用于IP摄像机、车载摄像机和USB摄像机等高分辨率智能视频录制应用。该芯片包括32位双核RISC处理器、高级图像信号处理器&#xff08;ISP&#xff09;、高性能MJPEG/H.264/H.26…

Maven-三、聚合

Maven 文章目录 Maven前言创建聚合模块设置管理的子模块总结 前言 在使用了maven进行多模块开发后&#xff0c;随着模块变多会变得难以管理&#xff0c;所以需要使用聚合模块进行统一管理。 分模块开发的项目中会有多个模块&#xff0c;那么可以单独使用一个模块专门管理整个工…

毫米波雷达预警功能 —— 倒车预警(RCTA)

文档声明&#xff1a; 以下资料均属于本人在学习过程中产出的学习笔记&#xff0c;如果错误或者遗漏之处&#xff0c;请多多指正。并且该文档在后期会随着学习的深入不断补充完善。感谢各位的参考查看。 笔记资料仅供学习交流使用&#xff0c;转载请标明出处&#xff0c;谢谢配…

【Web】御网杯信息安全大赛2024 wp(全)

目录 input_data admin flask 如此多的FLAG 一夜醒来之全国CTF水平提升1000倍&#x1f60b; input_data 访问./.svn后随便翻一翻拿到flag admin dirsearch扫出来 访问./error看出来是java框架 测出来是/admin;/路由打Spring View Manipulation(Java)的SSTI https:/…

HTML中直接创建一个“onoff”图形开关包括css+script

1. HTML中直接创建一个“onoff”图形开关 下面是一个完整的HTML文档示例 在HTML中直接创建一个“onoff”图形开关&#xff08;通常指的是一个类似于物理开关的UI组件&#xff0c;可以切换开或关的状态&#xff09;&#xff0c;并不直接支持&#xff0c;因为HTML主要用于内容的…

[数据集][目标检测]中草药类型识别检测数据集VOC+YOLO格式7976张45类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;7976 标注数量(xml文件个数)&#xff1a;7976 标注数量(txt文件个数)&#xff1a;7976 标注…

STM32篇:按键点亮LED灯

输入&#xff08;按键&#xff09;&#xff1a;KEY1---PA0 KEY2---PA1 输出&#xff08;LED灯&#xff09;&#xff1a;LED1---PB8 LED2---PB9

数字孪生技术如何推动企业可持续发展:监控与优化企业可持续目标的新视角

数字孪生助力可持续发展的新机遇 在全球推进可持续发展战略的背景下&#xff0c;企业需要创新型的技术工具来实现高效管理&#xff0c;数字孪生技术成为了实现这一目标的重要工具。数字孪生通过虚拟与现实的互动&#xff0c;将物理世界中的企业活动、运营数据及生产流程进行精…

FreeSWITCH 简单图形化界面29 - 使用mod_xml_curl 动态获取配置、用户、网关数据

FreeSWITCH 简单图形化界面29 - 使用mod_xml_curl 动态获取配置、用户、网关数据 FreeSWITCH GUI界面预览安装FreeSWITCH GUI先看使用手册1、简介2、安装mod_xml_curl模块3、配置mod_xml_curl模块3、编写API接口4、测试一下5、其他注意的地方 FreeSWITCH GUI界面预览 http://m…

LDO选型

LDO原理 mos管工作在可变电阻区&#xff0c;输出端电压会因为输出负载的变化而变化&#xff0c;则可通过误差放大器来控制Rds从而维持输出电压不变&#xff0c;行成一个动态平衡。 低压差 线性调整率 负载调整率 电源&#xff08;纹波&#xff09;抑制比 瞬态响应 外部元器件作…

神经网络(二):卷积神经网络

文章目录 一、图像的本质1.1单通道图像&#xff1a;灰度图1.2多通道图像 二、卷积神经网络2.1基本结构2.2卷积层2.2.1卷积操作2.2.2填充padding2.2.3步幅strides2.2.4多通道图像卷积&#xff1a;单卷积核2.2.5多通道图像卷积&#xff1a;多卷积核2.2.5卷积层的参数与激活函数 2…

算法练习题24——leetcode3296移山所需的最小秒数(二分模拟)

【题目描述】 【代码示例&#xff08;java&#xff09;】 class Solution {// 计算让工人们将山的高度降到0所需的最少时间public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) {long left 0; // 最少时间初始为0long right 0; // 最大时间初始化为0// …

Linux,uboot,kernel启动流程,S5PV210芯片的启动流程,DRAM控制器初始化流程

一、S5PV210芯片的DRAM控制器介绍、初始化DDR的流程分析 1、DRAM的地址空间 1)从地址映射图可以知道&#xff0c;S5PV210有两个DRAM端口。 DRAM0的内存地址范围&#xff1a;0x20000000&#xff5e;0x3FFFFFFF&#xff08;512MB&#xff09;&#xff1b;DRAM1:的内存地址范围…