JVM——引言+JVM内存结构

这篇具有很好参考价值的文章主要介绍了JVM——引言+JVM内存结构。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

什么是JVM

定义:

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

好处:

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

比较:

jvm jre jdk

JVM——引言+JVM内存结构,JVM,jvm

学习jvm的作用

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

常见的jvm

自己百度查找

jvm的组成

JVM——引言+JVM内存结构,JVM,jvm

 内存结构

程序计数器

定义

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

作用

如下图所示

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

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

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

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

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

JVM——引言+JVM内存结构,JVM,jvm

 特点:

线程私有

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

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

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

JVM——引言+JVM内存结构,JVM,jvm

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

虚拟机栈

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

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

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

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

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

JVM——引言+JVM内存结构,JVM,jvm

 定义

Java Virtual Machine Stacks (Java 虚拟机栈)

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

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

问题辨析

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

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

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

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

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

        JVM——引言+JVM内存结构,JVM,jvm

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

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

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

JVM——引言+JVM内存结构,JVM,jvmJVM——引言+JVM内存结构,JVM,jvm

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

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

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

栈内存溢出

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

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

JVM——引言+JVM内存结构,JVM,jvm

JVM——引言+JVM内存结构,JVM,jvmJVM——引言+JVM内存结构,JVM,jvm

 在将对象转换成json对象时也会有栈溢出,这种两个类的循环问题会导致json解释器出现问题。JVM——引言+JVM内存结构,JVM,jvm

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

 JVM——引言+JVM内存结构,JVM,jvm

线程运行诊断

案例1: cpu 占用过多
JVM——引言+JVM内存结构,JVM,jvm

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

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

JVM——引言+JVM内存结构,JVM,jvm

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

JVM——引言+JVM内存结构,JVM,jvm

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

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

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

JVM——引言+JVM内存结构,JVM,jvm 在jstack 输出内容中可以看见一个nid=Ox7f99的线程,状态为RUNNABLE.

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

JVM——引言+JVM内存结构,JVM,jvm

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

  • nid (Node ID) 是指在分布式系统中,每个节点的唯一标识
  • pid (Process ID) 是指操作系统中每个进程的唯一标识。
  • tid (Thread ID) 是指操作系统中每个线程的唯一标识。
案例2: 程序运行很长时间没有结果

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

JVM——引言+JVM内存结构,JVM,jvm

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

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

JVM——引言+JVM内存结构,JVM,jvm

本地方法栈

JVM——引言+JVM内存结构,JVM,jvm

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

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

JVM——引言+JVM内存结构,JVM,jvm

 

定义

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

特点:

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

堆内存溢出

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

JVM——引言+JVM内存结构,JVM,jvm

 运行结果:  溢出内存错误: java 堆 空间JVM——引言+JVM内存结构,JVM,jvm

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

JVM——引言+JVM内存结构,JVM,jvm JVM——引言+JVM内存结构,JVM,jvm

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

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

堆内存诊断

相关工具:

1.jps 工具

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

2. jmap 工具

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

3.jconsole 工具 

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

4.jvisualVM 工具

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

案例1

JVM——引言+JVM内存结构,JVM,jvm

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

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

JVM——引言+JVM内存结构,JVM,jvm

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

 JVM——引言+JVM内存结构,JVM,jvm

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

 1~2之间

数组创建之前使用了6Mb

JVM——引言+JVM内存结构,JVM,jvm

 2~3之间

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

JVM——引言+JVM内存结构,JVM,jvm

 3之后

垃圾回收之后变成1.2mb

JVM——引言+JVM内存结构,JVM,jvm

使用jconsole工具的界面。

JVM——引言+JVM内存结构,JVM,jvm

 案例2

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

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

JVM——引言+JVM内存结构,JVM,jvm

 新生代剩8mbJVM——引言+JVM内存结构,JVM,jvm

JVM——引言+JVM内存结构,JVM,jvm 老年代剩200mb

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

 JVM——引言+JVM内存结构,JVM,jvm

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

JVM——引言+JVM内存结构,JVM,jvm

 查看最大的ArrayList实例的具体信息JVM——引言+JVM内存结构,JVM,jvm

 源代码

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

JVM——引言+JVM内存结构,JVM,jvm

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

方法区

定义

按照jdk_jvm_1.8中的定义

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

组成

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

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

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

JVM——引言+JVM内存结构,JVM,jvm

 方法区内存溢出

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

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

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

-XX:MaxMetaspaceSize=8m  元空间

-XX:MaxPermSize=8m  永久代

JVM——引言+JVM内存结构,JVM,jvm

元空间运行报异常 

JVM——引言+JVM内存结构,JVM,jvm

 永久代报异常JVM——引言+JVM内存结构,JVM,jvm

 场景:

  • spring
  • mybatis

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

运行时常量池

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

JVM——引言+JVM内存结构,JVM,jvm

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

javap -v HelloWorld.class

常量池部分

JVM——引言+JVM内存结构,JVM,jvm

 虚拟机指令部分

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

ldc是找到一个引用地址。

JVM——引言+JVM内存结构,JVM,jvm

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

 运行时常量池里面#1,#2...这些会变成内存地址。文章来源地址https://www.toymoban.com/news/detail-672250.html

到了这里,关于JVM——引言+JVM内存结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • JVM-内存结构

    JVM-内存结构

    1、定义 程序计数器(Program Counter)是JVM中的一块较小的内存区域,它是一个指向当前线程正在执行的字节码指令的指针。 程序计数器使用的是寄存器 ,特点-快。 程序计数器作用是 记住下一条jvm执行的执行地址。 特点: 线程私有的 不会存在内存溢出-jvm规定了 2、作用 程

    2024年02月15日
    浏览(9)
  • JVM 内存结构快速入门

    JVM 内存结构快速入门

      Java 内存模型(Java Memory Model,JMM)是一种规范,定义了 Java 程序中多线程并发访问共享变量时的行为和规则。   线程共享:方法区、堆   线程独有:栈、程序计数器 2.1 方法区   方法区是JVM中的一块内存区域,在JVM启动时被创建,与堆内存分开管理。方法区的大

    2024年02月12日
    浏览(14)
  • 【JVM 内存结构丨栈】

    【JVM 内存结构丨栈】

    主页传送门:📀 传送   栈是用于执行线程的内存区域,它包括局部变量和操作数栈。 Java 虚拟机栈会为每一个即将运行的 Java 方法创建一块叫做“栈帧”的区域,用于存放该方法运行过程中的一些信息,如: 局部变量表 操作数栈 动态链接 方法出口信息 … 图示如下 :

    2024年02月11日
    浏览(9)
  • 复习一下JVM内存结构

    程序计数器内存很小,可以看作是 当前线程 所执行字节码的 行号指示器 。 有了它,程序就能被正确的执行。 因为有 线程切换 的存在,则每个线程必须有各自独立的程序计数器,即 线程私有 的内存。 这里再解释一下什么是 线程切换 ,线程切换指的是: 单处理器在执行

    2024年02月20日
    浏览(14)
  • JVM内存结构介绍

    JVM内存结构介绍

    一、java代码编译执行过程   1.源码编译:通过Java源码编译器将Java代码编译成JVM字节码(.class文件)   2.类加载:通过ClassLoader及其子类来完成JVM的类加载   3.类执行:字节码被装入内存,进入JVM虚拟机,被解释器解释执行         注:Java平台由Java虚拟机和Java应用程序接口

    2024年02月16日
    浏览(12)
  • JVM 内存结构

    JVM 内存结构

    Java 虚拟机的内存空间分为 5 个部分: 程序计数器 Java 虚拟机栈 本地方法栈 堆 方法区 JDK 1.8 同 JDK 1.7 比,最大的差别就是:元数据区取代了永久代。元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在

    2024年02月11日
    浏览(10)
  • JVM内存结构

    JVM内存结构

    类加载:类源代码经编译器编译为二进制字节码,通过 类加载器 加载到JVM JVM内存:类存放 方法区 ,实例对象存放 堆 中,方法调用时用到 虚拟机栈、程序计数器、本地方法栈 执行引擎: 解释器 逐行解释执行方法代码,热点代码由 JIT 做编译、优化后的执行, GC 负责回收堆中不再被引

    2024年01月25日
    浏览(12)
  • JVM学习笔记(二)内存结构

    JVM学习笔记(二)内存结构

    目录   一、JVM内存结构 1. 虚拟机栈(JVM Stacks) 1)定义 2)栈内存溢出 3) 线程运行诊断 案例1:CPU占用过高 案例2:程序运行很长时间没有结果​编辑 2. 本地方法栈(Native Method Stacks) 3.  堆(Heap) 1)定义 2)特点 3)堆内存溢出 4)堆内存诊断 5)案例:垃圾回收后,内存

    2024年02月16日
    浏览(12)
  • 【JVM 内存结构 | 程序计数器】

    【JVM 内存结构 | 程序计数器】

    主页传送门:📀 传送 Java 虚拟机的内存空间由 堆、栈、方法区、程序计数器和本地方法栈五部分组成。   JVM(Java Virtual Machine)内存结构包括以下几个部分: 堆区(Heap):堆区是最大的一块内存区域,由所有线程共享。所有的对象实例以及数组都在这块内存中分配。 方

    2024年02月11日
    浏览(14)
  • [JVM] 2. 类加载子系统(1)-- 内存结构、类加载子系统概述

    [JVM] 2. 类加载子系统(1)-- 内存结构、类加载子系统概述

    类加载子系统的职责是:加载class文件到内存中。 完整的内存结构如下: 类加载过程总体分为Loading(加载)、Linking(链接)、Initialization(初始化)三个环节,在Linking阶段又细分为Verification(验证)、Preparation(准备)、Resolution(解析)三个环节。 通过一个类的全限定名获

    2024年02月16日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包