JVM——引言+JVM内存结构

引言

什么是JVM

定义:

Java VirtualMachine -java 程序的运行环境 (ava 二进制字节码的运行环境)

好处:

  • 一次编写,到处运行
  • 自动内存管理,垃圾回收功能
  • 数组下标越界检查,
  • 多态

比较:

jvm jre jdk

学习jvm的作用

  • 面试
  • 理解底层实现原理
  • 中高级程序员的必备技能

常见的jvm

自己百度查找

jvm的组成

 内存结构

程序计数器

定义

Program Counter Register 程序计数器(寄存器)

作用

如下图所示

右边就是简单的java代码打印操作,编译成左侧的二进制字节码。

经过解释器——>机器码——>CPU执行。

程序计数器在这里面的作用就是记住下一条jvm指令的执行地址。

第一条指令地址是0,第一条指令交给解释器去执行的同时会把第二条指令的地址3放入程序计数器。第一条执行完之后,解释器会去取出3来执行......

物理实现: 通过CPU中寄存器(速度快)实现

 特点:

线程私有

每个线程都有自己的程序计数器。

每一个线程会有被分配一个时间片,在当前时间片内不能执行完会去执行别的线程的代码,直到轮到下一个时间片。

切换到别的线程时要记住当前执行到哪里,还是要用到程序计数器。通过私有的程序计数器知道下一行代码的地址。

 唯一不会存在内存溢出的区

虚拟机栈

栈是一种普通的先进后出的数据结构。

java的虚拟机栈则是线程运行需要的内存空间

一段代码有多个方法组成,一个栈帧表示一次方法的调用,栈帧就是每个方法运行需要的内存

运行:调用第一个方法时会给第一个方法划分一个栈帧空间,并压入栈内,执行完后会出栈,也会释放该方法占用的内存。

然后方法1调用方法2时会产生一个方法2的栈帧并入栈,然后方法2调用方法3也会产生并入栈,如下图所示。

 定义

Java Virtual Machine Stacks (Java 虚拟机栈)

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

栈帧大小由方法里的参数以及局部变量的个数决定 

问题辨析

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

   栈内存是一次次方法调用产生的栈帧内存,调用结束后会弹出栈,会自动回收,不需要垃圾回收     管理,垃圾回收是回收堆内存中的无用对象。

2.栈内存分配越大越好吗?

运行java代码时是可以指定栈内存大小的,使用-Xss size,下图还有不同系统下默认栈内存的大小和设定内存的示例。

栈内存越大会让线程数变少,512mb的物理内存下,每个线程的栈内存设置1mb大小可以运行512个,设置2mb大小可以运行256个线程。不会提高线程效率,但可以增加递归的层数。

        

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

        根据该变量是每个线程共享还是线程私有判断。下图是一个方法,方法内有一个局部变量。

该方法被调用两次时会有两个不同的栈。每个线程都会有私有的局部变量。因此这里不会有线程干扰的问题。

 假如将x改为static int x=0;的话就会出现线程干扰,如果不加保护的话会有线程安全问题。

总结:共享需要考虑线程安全,私有就不需要考虑。

  • 如果方法内的局部变量没有逃离方法的作用范围,则是线程安全。
  • 如果是局部变量引用了对象,并逃离方法的作用方法,需要考虑线程安全(引用传递和值传递的问题)

栈内存溢出

  • 栈帧过多导致栈内存溢出(栈帧过多爆栈)  :  通常在的递归导致。
  • 单片栈帧过大导致栈内存溢出(太大了,已经塞满了)

 一般不会有单片过大,栈帧里都是方法参数和局部变量。可以通过设置栈内存大小达到

 在将对象转换成json对象时也会有栈溢出,这种两个类的循环问题会导致json解释器出现问题。

 可以通过一个@JsonIgnore注解达到在json转换对象时忽略变量的效果。 

 

线程运行诊断

案例1: cpu 占用过多

 linux环境下运行一段java代码导致cpu占用过高,可以使用top命令定位到哪一个进程占用,但看不见是哪一个线程导致的。

在linux下使用ps H -eo pid,tid,%cpu 命令可以看见所有线程的pid(进程号),tid(线程号),%cpu(cpu占用)。

使用ps H -eo pid,tid,%cpu | grep 32655   后面加上| grep pid过滤无关进程的线程。

  • 用top定位哪个进程对cpu的占用过高
  • ps H -eo pid,tid,%cpu | grep pid (用ps命令进一步定位是哪个线程引起的cpu占用过高)
  • jstack 进程id  (可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号)

生产环境不推荐jstack,因为打印线程信息jvm会暂停其他线程 

然后将线程编号32665转换成16进制(7F99)在输出内容中查找 

 在jstack 输出内容中可以看见一个nid=Ox7f99的线程,状态为RUNNABLE.

看见问题出在第8行代码。如下图源码第8行是个死循环。

 nid、pid 和 tid 是计算机系统中常用的三个标识

  • nid (Node ID) 是指在分布式系统中,每个节点的唯一标识
  • pid (Process ID) 是指操作系统中每个进程的唯一标识。
  • tid (Thread ID) 是指操作系统中每个线程的唯一标识。

案例2: 程序运行很长时间没有结果

线程死锁导致的无结果下使用jstack命令查看,下输出内容最后可以看见有关死锁信息。

 两个线程都想获得a,b,但是都在等对方放开拥有的对象,然后陷入死锁。

产生死锁的四个必要条件:互斥、不可剥夺、请求和保持、循环等待。

本地方法栈

定义:    java虚拟机在调用本地方法时需要给本地方法提供的内存空间

在Object这个类中就有很多,比如Object的clone方法的声明是native,这个native的实现是c/c++,java代码是间接调用native

 

定义

通过 new 关键字,创建对象都会使用堆内存

特点:

  • 它是线程共享的,堆中对象都需要考虑线程安全的问题
  • 有垃圾回收机制 (不再被引用的对象会被回收) 

堆内存溢出

下图所示方法中String类型的对象a会一次次变大,直至堆溢出。

 运行结果:  溢出内存错误: java 堆 空间

使用-Xmx size改变堆空间大小。

 

 修改前26次才溢出,修改后17次溢出。

有可能堆内存较大,运行时间短,在系统前期看不出问题,后期才会爆掉,故测试时可以将堆内存设置较小进行排查。

堆内存诊断

相关工具:

1.jps 工具

        查看当前系统中有哪些 java 进程

2. jmap 工具

        查看堆内存占用情况 jmap -heap 进程id (只能看某一瞬间的情况)

3.jconsole 工具 

        图形界面的,多功能的监测工具,可以连续监测

4.jvisualVM 工具

        图形化界面,可以抓取当前快照 

案例1

 new一个10MB的数组对象,后面置为null,然后gc显式回收。

运行后通过jps查看进程id,jmap -heap 18756在1~2,2~3,3之后三个时间点抓取快照信息。 

最大堆内存占用MaxHeapSize是4个G 

 

Eden Space就是专门为new 出来的对象准备的。 

 1~2之间

数组创建之前使用了6Mb

 2~3之间

创建数组对象之后使用16mb,

 3之后

垃圾回收之后变成1.2mb

使用jconsole工具的界面。

 案例2

垃圾回收之后,内存占用任然很高。

新生代被回收了,老年代没有被回收。

 新生代剩8mb

 老年代剩200mb

使用新的工具jvisualvm可视化虚拟机

 

保存快照之后进行查找最大的类 

 查看最大的ArrayList实例的具体信息

 源代码

两百个Student对象,每个都开了一个1mb大小的byte数组。并且一直在作用范围内,无法回收,内存占用居高不下。

 通过可视化界面的堆 dump按钮进行排查。 

方法区

定义

按照jdk_jvm_1.8中的定义

  • 方法区是所有java虚拟区线程共享的区域。
  • 存储了和类的结构相关的信息。
  • 有成员变量filed,method data方法数据,成员方法、构造器方法的代码以及运行时常量值run-time constant pool等等
  • 在虚拟机启动时被创建
  • 逻辑上是堆的组成部分(1.8以前用的堆内存,1.8以后用的是系统内存
  • 方法区也会导致内存溢出

组成

永久代和元空间都是方法区这个概念的实现。

永久代和元空间最本质的区别就是 前者使用的是jvm内存 后者使用的是操作系统内存。

图中常量池是运行时常量池。

 方法区内存溢出

  • 1.8 以前会导致永久代内存溢出
  • 1.8 之后会导致元空间内存溢出

下图代码就是一个加载了10000个类的代码,最外层继承实现了类加载器,在循环内指定版本号,类名,包名,父类,接口等信息创建一个新类。

这里元空间和永久代都没有设置上限,这里需要设置元空间和永久代大小。

-XX:MaxMetaspaceSize=8m  元空间

-XX:MaxPermSize=8m  永久代

元空间运行报异常 

 永久代报异常

 场景:

  • spring
  • mybatis

spring和mybatis都使用到了cglib技术。

运行时常量池

下面的这段代码的二进制字节码含有如下信息。 

使用如下命令查看该代码反编译后的结果

javap -v HelloWorld.class

常量池部分

 虚拟机指令部分

执行指令时下面第一条就是获取静态变量,#2在常量池里面找。

ldc是找到一个引用地址。

 定义:

  • 常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
  • 运行时常量池,常量池是*.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

 运行时常量池里面#1,#2...这些会变成内存地址。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

目标检测(Object Detection)

文章目录 1. 目标检测1.1 目标检测简要概述及名词解释1.2 IOU1.3 TP TN FP FN1.4 precision(精确度)和recall(召回率) 2. 边框回归Bounding-Box regression3. Faster R-CNN3.1 Faster-RCNN:conv layer3.2 Faster-RCNN&…

Photoshop制作漂亮光泽感3D按钮

原文链接(https://img-blog.csdnimg.cn/45472c07f29944458570b59fe1f9a0e0.png)

直线导轨的选购要素

直线导轨是用来支撑和引导运动部件,按给定的方向做往复直线运动,主要用于精密机床、坐标测量机和大型机床,对于我们整个国民生产、生活活动都起着至关重要的作用。 我们在选购直线导轨时,都想要选到质量好的,那么我们要…

手把手教学——终端工具xshell与文件传输工具xftp使用步骤及详解

前言 xshell是一款常用于连接本地linux服务以及云服务器的终端远程连接工具,该款终端工具常搭配远程文件传输工具xftp一起使用,由于还有很多小伙伴还不知道这两款终端工具的使用流程及步骤,Darren洋在这里给小伙伴们进行详细讲解。 一、下载工…

慎用!澳洲留学生用ChatGPT写论文被控学术不端!AI论文漏洞百出,各高校已加强捡测!

自从进入ChatGPT时代以来,留学生们纷纷表示写作业,so easy。留学生们在用AI写论文时候没有预计到的是,ChatGPT存在杜撰文献的问题,并且学校已经在使用AI检测工具。 目前全澳大多数大学都可以选择使用现在很流行的反剽窃软件服务T…

合并多个文本文件

使用 wxPython 模块合并多个文本文件的博客。以下是一篇示例博客: C:\pythoncode\blog\txtmerge.py 在 Python 编程中,我们经常需要处理文本文件。有时候,我们可能需要将多个文本文件合并成一个文件,以便进行进一步的处理或分析。…

图像编程补充:计算机图形学和数字图像处理概念

一、计算机图形学 国际标准化组织(ISO)的定义:计算机图形学是研究通过计算机将数据转换为图形,并在专门显示设备上显示的原理、方法和技术的学科。 1.1什么是计算机图形学 图形的构成要素: 图形的广义概念&#xff1…

C语言——通讯录详解(动态版)

通讯录详解 前言:一、定义一个通讯录二、初始化三、增加联系人3.1 给通讯录扩容3.2增加联系人 四、释放内存五、完整代码 前言: 我们已经学过了通讯录的静态版,但是它的缺点很明显,通讯录满了就添加不了联系人了啦。我再让通讯录升…

《Linux从练气到飞升》No.15 Linux 环境变量

🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的…

【linux基础(四)】对Linux权限的理解

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:Linux从入门到开通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学更多操作系统知识   🔝🔝 Linux权限 1. 前言2. shell命…

2023 最新 小丫软件库app开源源码 PHP后端

上传了源码解压之后,在admin/public/config.php修改后台登录账号和密码 后台地址:域名或者ip/admin 然后自己修改配置即可 后端搭建完成,现在导入iapp源码 导入iapp源码之后,修改mian.iyu载入事件的对接api和url就可以打包了 sss …

哈工大开源“活字”对话大模型

一、介绍 大规模语言模型(LLM)在自然语言处理的通用领域已取得了令人瞩目的成功。对于广泛的应用场景,这种技术展示了强大的潜力,学术界和工业界的兴趣也持续升温。哈工大自然语言处理研究所30余位老师和学生参与开发了通用对话大…

小米分享 | 解密面试题:网易面试如何回答“创建线程有哪几种方式?”

大家好,我是你们的小米!今天要和大家一起探讨一个在技术面试中常见的问题:创建线程有哪几种方式?这可是个经典面试题哦!不过别担心,小米在这里为你详细解析,帮你轻松应对,让你在面试…

stm32控制蜂鸣器源代码(附带proteus线路图)

说明: 1 PB0输出0时,蜂鸣器发生; 2 蜂鸣器电阻值如果太大会导致电流太小,发不出声音; 3蜂鸣器额定电压需要设置得低一点,可以是2V,但不能高于3V,这更右上角的电阻值有关系&#x…

【Linux】make/makefile自动化构建工具

文章目录 前言一、什么是make/makefile?二、依赖关系和依赖方法2.1 makefile中创建文件2.2 makefile中删除文件2.3 stat指令查看文件的三种时间(ACM)2.4 伪目标文件(.PHONY) 三、Makefile中的一些特殊符号3.1 $ 和 $^3…

【深入理解ES6】字符串和正则表达式

概念 字符串(String)是JavaScript6大原始数据类型。其他几个分别是Boolean、Null、Undefined、Number、Symbol(es6新增)。 更好的Unicode支持 1. UTF-16码位 字符串里的字符有两种: 前 个码位均以16位的编码单元…

尚硅谷大数据项目《在线教育之离线数仓》笔记002

视频地址:尚硅谷大数据项目《在线教育之离线数仓》_哔哩哔哩_bilibili 目录 P025 P026 P027 P028 P029 P030 P031 P032 P033 P034 P035 P036 P037 P038 P025 在Hive所在节点部署Spark P026 3)Hive on Spark测试 (1)…

深度剖析数据在内存中的存储

目录 一、数据类型介绍 类型的基本归类 1.整形家族 2.浮点数家族 3.构造类型 (自定义类型) 4.指针类型 5.空类型 二、整形在内存中的存储 1.原码、反码、补码 1.1原码 1.2反码 1.3补码 1.4计算规则 2 .大小端介绍 三、浮点型在内存中的存…

C++函数模板和类模板

C另一种编程思想称为泛型编程,主要利用的技术是模板 C提供两种模板机制:函数模板和类模板 C提供了模板(template)编程的概念。所谓模板,实际上是建立一个通用函数或类, 其类内部的类型和函数的形参类型不具体指定, 用…

算法与数据结构(七)--堆

一.堆 1.堆的定义 堆是计算机科学中一类特殊的数据结构的通常,堆通常可以被看做是一颗完全二叉树的数组对象。 堆的特性 1.它是完全二叉树,除了树的最后一层结点不需要是满的,其他的每一层从左到右都是满的,如果最后一层结点不…