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

引言

本文主要介绍一下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.xdnf.cn/news/1543016.html

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

相关文章

ElasticSearch分页查询性能及封装实现

Es的分页方式 fromsize 最基本的分页方式&#xff0c;类似于SQL中的Limit语法&#xff1a; //查询年龄在12到32之间的前15条数据 {"query":{"bool":{"must":{"range":{"user_age":{"gte":12,"lte":3…

vue实现数据栏无缝滚动实现方式-demo

效果 方式一 通过实现两个item 进行循环 <!--* Author: Jackie* Date: 2023-08-16 21:27:42* LastEditTime: 2023-08-16 21:41:51* LastEditors: Jackie* Description: scroll 水平滚动 - 效果基本满足需求* FilePath: /vue3-swiper-demo/src/components/scroll/Scroll12.…

Linux线程同步与互斥

&#x1f30e;Linux线程同步与互斥 文章目录&#xff1a; Linux线程同步与互斥 Linux线程互斥 线程锁       互斥量Mutex         初始化互斥量的两种方式         申请锁方式         解除与销毁锁 问题解决及线程饥饿       互斥锁的底…

MWD天气图像多分类数据集,用于图像分类总共6个类别,多云,下雨,下雪,雾天,正常天气,共60000张图像数据

MWD天气图像多分类数据集&#xff0c;用于图像分类 总共6个类别&#xff0c;多云&#xff0c;下雨&#xff0c;下雪&#xff0c;雾天&#xff0c;正常天气&#xff0c;共60000张图像数据 MWD天气图像多分类数据集 (Multi-Weather Dataset, MWD) 数据集描述 MWD天气图像多分类…

AcWing算法基础课-790数的三次方根-Java题解

大家好&#xff0c;我是何未来&#xff0c;本篇文章给大家讲解《AcWing算法基础课》790 题——数的三次方根。本题考查算法为浮点数二分查找。本文详细介绍了一个使用二分法计算浮点数三次方根的算法。通过逐步逼近目标值&#xff0c;程序能够在给定的区间内精确计算出结果&…

【Elasticsearch系列廿】Logstash 学习

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

什么是Rspack?

Rspack 是一个基于 Rust 编写的高性能 JavaScript 打包工具&#xff0c;旨在提供与 webpack 生态系统的强兼容性&#xff0c;允许无缝替换 webpack&#xff0c;并提供极快的构建速度。 介绍 - Rspack 它由字节跳动 Web Infra 团队孵化&#xff0c;具有以下特点&#xff1a; 高…

2024年汉字小达人区级自由报名备考冲刺:最新问题和官模题练一练

2024年第十一届汉字小达人的区级活动的时间9月25-30日正式开赛&#xff0c;还有两天就开始比赛。 今天继续回答几个关于汉字小达人的最新问题&#xff0c;做几道2024年官方模拟题&#xff0c;帮助孩子们更精准地备考2024年汉字小达人。 【温馨提示】本专题在比赛期间持续更新…

委托的注册及注销+观察者模式

事件 委托变量如果公开出去&#xff0c;很不安全&#xff0c;外部可以随意调用 所以取消public,封闭它&#xff0c;我们可以自己书写两个方法&#xff0c;供外部注册与注销&#xff0c;委托调用在子方法里调用&#xff0c;这样封装委托变量可以使它更安全&#xff0c;这个就叫…

LLM大模型训练/推理的显卡内存需求计算

无论你是从头开始训练 LLM、对其进行微调还是部署现有模型&#xff0c;选择合适的 GPU 对成本和效率都至关重要。在这篇博客中&#xff0c;我们将详细介绍使用单个和多个 GPU 以及不同的优化器和批处理大小进行 LLM 训练和推理时 GPU 要求的所有信息。 计算机处理器由多个决定…

C/C++逆向:switch语句逆向分析

在逆向分析中&#xff0c;switch语句会被编译器转化为不同的底层实现方式&#xff0c;这取决于编译器优化和具体的场景。常见的实现方式包括以下几种&#xff1a; ①顺序判断&#xff08;if-else链&#xff09;&#xff1a; 编译器将switch语句转化为一系列的if-else语句。这…

管道物体计数系统源码分享

管道物体计数检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

信创背景下中职计算机组装与维护课程教学解决方案

在当前的国际形势下&#xff0c;确保信息化系统的安全性和可靠性显得尤为重要。为了提高信息技术的安全性和可靠性&#xff0c;国家鼓励并支持使用国产的信息技术、工具和资源来替代现有的技术体系。这一过程被称为“安全可信的创新替代”&#xff0c;它已经成为国家安全战略的…

VMware ESXi 8.0U3b macOS Unlocker OEM BIOS 2.7 标准版和厂商定制版

VMware ESXi 8.0U3b macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版 ESXi 8.0U3 标准版&#xff0c;Dell (戴尔)、HPE (慧与)、Lenovo (联想)、Inspur (浪潮)、Cisco (思科)、Hitachi (日立)、Fujitsu (富士通)、NEC (日电) 定制版、Huawei (华为) OEM 定制版 请访问…

OpenResty安装及使用

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

构建高可用和高防御力的云服务架构第四部分:REDIS(4/5)

本文的目的是深入探讨Redis在构建高可用和高防御力云服务架构中的应用。我们将分析Redis的工作原理、核心特性以及如何通过Redis优化云服务架构的性能和安全性。此外&#xff0c;我们还将提供实际案例和最佳实践&#xff0c;帮助读者更好地理解和应用Redis&#xff0c;以构建更…

中小企业体系技术抽象沉淀-异地灾备篇

IT团队内部使用工具 系列文章&#xff1a;https://blog.csdn.net/caicongyang/article/details/136857045 DDL DML管控 https://github.com/hhyo/Archery/ flyway 文档编写 wiki 技术对外输出文档推荐gitbook 同城双活数据同步方案 总览&#xff1a; vivo 系列文章&#x…

普通程序员如何快速入门AIGC

文章目录 第1阶段&#xff1a;基础知识打牢 (1-2周)第2阶段&#xff1a;深度学习理论与实践 (2-4周)第3阶段&#xff1a;AIGC 生成技术入门 (3-5周)第4阶段&#xff1a;进阶学习和项目实战 (5-8周)第5阶段&#xff1a;保持学习和更新 (持续进行) 要快速入门 AIGC&#xff08;AI…

SPI驱动学习六(SPI_Master驱动程序)

目录 前言一、SPI_Master驱动程序框架1. SPI传输概述1.1 数据组织方式1.2 SPI控制器数据结构 2. SPI传输函数的两种方法2.1 老方法2.2 新方法 二、如何编写SPI_Master驱动程序1. 编写设备树2. 编写驱动程序 三、SPI_Master驱动程序简单示例demo1. 使用老方法编写的SPI Master驱…

Webrtc开发实战系列 - win10+vs2022下编译最新webrtc代码

1. 准备起步 操作系统&#xff1a;windows 10 安装 vs2019/vs2022 安装 win10 sdk 19041 一定勾选 Debugging Tools for Windows 科学上网准备代理工具 磁盘剩余空间至少 30G 推荐用一台干净的机器或者虚拟机来编译WebRTC&#xff0c;安装过python的会出现一些非常棘手…