[转载] JVM(一):JVM体系结构详解

参考链接: JVM如何工作–JVM体系结构

JVM简介        JVM是Java程序得以运行的平台,也是Java程序可以跨平台的底层支撑,从整体上来看,JVM的主要功能可以分为加载和执行两大块。其中类加载器负责.class文件的寻址与加载,执行引擎负责字节码指令执行及内存的管理等等。下面是JVM一个经典的体系结构图 

类加载系统:关于类加载体系的详细说明在另一博客https://blog.csdn.net/w1673492580/article/details/81838835 

运行时数据区宏观角度:         从宏观角度来看,JVM运行时数据区的各部分划分很明显,方法区用于存储类数据,堆用于存储Java程序在运行过程中创建的所有对象,栈和PC寄存器属于线程独有,栈代表线程执行过程中所有方法调用信息(比如比如入参、局部变量、中间结果,返回信息等等),PC寄存器即计数器,代表指令在主存中的地址,每执行一条指令后PC+1,即指向下一条指令。本地方法栈即通过Java调用本地方法时的相关信息,但与调用Java方法不一样,调用Java方法时JVM会当前Java栈中压入一个新的栈桢,而调用本地方法则不会修改Java栈,从这个角度看,本地方法栈可以理解成JVM运行时数据区的一个扩展。 

微观角度:堆:Java程序在运行过程中(加载也是运行的一部分)创建的所有对象都位于堆内存中,且JVM中堆内存在设计上是多线程共享的,所以堆中数据的访问也必须进行安全控制;        由于运行期间很可能会创建大量的对象,而且大部分对象都是小而短的(占用空间小及生命周期短),所以堆内存的管理也尤其重要,但JVM中并没有释放对象的指令,这表示开发中不能通过代码去管理对象的释放,所以JVM内置了垃圾回收器来管理,堆也是垃圾回收主要集中的地方(对于栈由于栈桢的大小可以在编译期就根据类结构数据确定,所以这部分的回收具有一定的确定性)。       在Java代码中,通过obj.getClass()获取对象所属的类,也可以通过new  ClassName()创建一个对象。这是因为在JVM中对象数据包含了一个指向方法区中对应类型信息的指针,可以通过该指针获取对应类信息。反过来JVM也可以根据方法区中类信息创建该类对象,甚至知道该类对象应该占用多少空间(但实际分配大小依赖于JVM实现)。同样通过class.getClassLoader()可以获取当前类加载器也是同样的原理。        还有个比较有意思的就是对象锁synchronized(obj),Java中每个对象都可以作为锁,同样也是因为对象本身包含了一个指向锁数据的指针,但由于绝大部分对象的锁都用不到,所以大部分JVM的实现,都只在第一个线程尝试获取对象锁时,才给该对象分配对应的锁数据。       关于堆空间本身的设计依赖具体的实现,下面是两种完全不同的可能设计,第一种把堆内存划分为句柄池和对象池两部分,对对象的引用指向句柄池,句柄池中每个元素又由两部分组成,一个指向方法区中的存放类数据的地址,一个指向对象池中的对象。这样的优势体现在,当垃圾回收器 回收内存并重新划分导致对象内存地址发生变化时,不需要更新所有引用的指向,而只需要更新句柄池中指向对象的指针,缺点就是中间需要额外经过一次查找。 

第二种设计引用直接指向堆中的对象,这样的优缺点和第一种设计刚好相反,不需要额外的查找,但对象地址发生变化时,需要更新所有引用。 

方法区:方法区在设计上也是所有线程共享,主要存储类相关信息(如字段/方法信息、常量池信息、对当前ClassLoader和Class的引用等等),在JVM加载某个类时,会抽取出对应.class文件中类相关的信息并以某种结构(依赖于JVM实现)存到方法区中,当程序运行时,JVM则会到方法区中去查找使用对应类信息(比如创建对象)。        值得注意的一点是由于所有线程共享方法区中的数据,所以方法区中数据的访问必须被设计成线程安全的,比如说多个线程并发加载同一类等等。另外方法区虽然也被称为“永久代”,但实际上其中的数据也是可以被垃圾回收器回收的,回收内容主要包括常量池中无用的常量、无用的类(具体判断依据请参考垃圾回收篇)。         虽然类信息具体的存储结构依赖于具体JVM实现,但为了提高方法的检索效率,部分JVM实现会为每个非抽象类生成一个方法表(方法表虽然加快了检索速度,但本身也会占用一定的内存空间,算是以空间换时间),方法表是一种数组结构,每个元素代表一个方法实例(从Java角度来说,每个元素就相当于一个Method对象)。这种情况下,对象不再直接指向方法区中的存放类信息的地址,而是指向方法表,通过方法表来间接关联对象与类型信息,从JVM的角度来看其基本指向如下图 

Java栈与PC寄存器:JVM中每个线程都有自己的PC寄存器和Java栈,PC寄存器即计数器,表示指令在主存中的地址,每执行一条指令后PC+1,即指向下一条指令。Java栈代表线程在执行过程中的所有方法调用信息,JVM对栈只有压入栈桢和弹出栈桢两个操作,“栈”由"栈桢“组成,线程每调用一次方法JVM即会为它产生并压入一个“栈桢”,方法执行完毕即会弹出对应的栈桢,栈桢本质上就是一个内存片,用来存储方法局部变量和计算的中间结果,其中用于存储中间结果的部分又称为“操作数栈”,所以操作的数据即可能是“操作数栈”中的数据,也可能是“栈桢”中的数据。 值得注意的是局部变量和操作数栈的大小在编译时计算出来,并放置到class文件中,然后JVM就可以知道方法栈桢的大小,当调用一个方法时jvm将压入一个适当大小的栈桢至栈中,但栈在jvm中是有深度限制的,当线程调用的栈深度超出该限制时将抛出StockOverflowErro异常,如果jvm在扩展栈时无法获取更多内存则会抛出OutofMemoryErro。下面关于Java栈的图文描述及验证代码   

public static void main(String[] args) throws InterruptedException {

//         testStackOverflowError();

        testOutOfMemoryError();

    }

    

    public static void testStackOverflowError(){

        testStackOverflowError();

    }

    

    public static void testOutOfMemoryError(){

        byte[] bytes = new byte[2000000000];

    } 

本地方法栈:        本地方法栈即代表了线程在执行过程中调用本地方法的一系列信息,与Java栈不同的地方在于,本地方法并不受JVM的限制,对本地方法的调用不会导致JVM往Java栈中压入栈桢。关于本地方法与Java方法的调用可以简单的假设一下,假设某个线程在执行Java方法过程中调用了本地方法C1,且本地方法C1最终又调用了某Java方法,则在这个过程中JVM会先由Java栈进入本地方法栈最终又回到Java栈中,下图简单的描述了这种情况 

执行引擎:        执行引擎负责字节码指令的执行,方法的字节码流由一系列有序指令组成,指令又由一个单字节的操作码 + 0个或多个操作数组成。操作码表示需要执行的操作,操作数表示操作的数据,一般来源于当前栈桢中的局部变量或当前Java栈桢中操作数栈的顶部,至于操作数的个数,由操作码决定(操作码本身就决定了它是否需要操作数,以及操作数的形式等等)。        不同的JVM中执行引擎也可能不同,最简单同时效率也最低的执行引擎是一次性解释字节码,它在每次运行方法时都把字节码翻译成本地代码再执行; 其次是即时编译(JITC),它在第一次执行方法时,会把对应的字节码翻译成本地机器代码并缓存,后续调用就可以重用缓存的本地机器代码;另外一种是自适应优化器(特殊的即时编译器), JVM一开始也会解释字节码,但它会监视程序的活动,并记录活动过程中使用最频繁的代码,然后把这些代码编译成本地代码,而其它代码则继续采用解释的方式。下面是javap -c com.alibaba.fastjson.JSONObject.class反汇编后的部分信息 

 public static java.lang.String valueToString(java.lang.Object) throws org.zend.sdklib.internal.utils.json.JSONException;

   Code:

      0: aload_0

      1: ifnull        12

      4: aload_0

      5: aconst_null

      6: invokevirtual #304                // Method java/lang/Object.equals:(Ljava/lang/Object;)Z

      9: ifeq          16

     12: ldc_w         #261                // String null

     15: areturn

     16: aload_0

     17: instanceof    #635                // class org/zend/sdklib/internal/utils/json/JSONString

     20: ifeq          83

     23: aload_0

     24: checkcast     #635                // class org/zend/sdklib/internal/utils/json/JSONString

     27: invokeinterface #637,  1          // InterfaceMethod org/zend/sdklib/internal/utils/json/JSONString.toJSONString:()Ljava/lang/String;

     32: astore_1

     33: goto          46

     36: astore_2

     37: new           #52                 // class org/zend/sdklib/internal/utils/json/JSONException

     40: dup

     41: aload_2

     42: invokespecial #640                // Method org/zend/sdklib/internal/utils/json/JSONException."<init>":(Ljava/lang/Throwable;)V

     45: athrow

     46: aload_1

     47: instanceof    #92                 // class java/lang/String

     50: ifeq          58

     53: aload_1

     54: checkcast     #92                 // class java/lang/String

     57: areturn

     58: new           #52                 // class org/zend/sdklib/internal/utils/json/JSONException

     61: dup 

aload_0表示将第一个局部变量压入到当前操作数栈中,aload指令后跟着的操作数必须是对象引用,这里第一个局部变量也是引用,即参数Object。 ifnull 12表示弹出栈顶对象(即刚压入的参数obj),判断是否为null, 为null则跳转到偏移量为12的分支处,关于指令相关的更多信息这里就不说了

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

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

相关文章

数据库连接池的设计思路及java实现

2019独角兽企业重金招聘Python工程师标准>>> connectionPool.DBConnectionManager [java] view plain copy package connectionPool; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; i…

[转载] java虚拟机 jvm 出入java栈 栈空间内存分配

参考链接&#xff1a; Java虚拟机(JVM)堆栈区域 java栈空间是一块线程私有的内存空间&#xff0c;java堆和程序数据密切相关&#xff0c;那么java栈就是和线程执行密切相关。线程最基本的执行行为就是函数的调用。每次函数调用其实是通过java栈传递数据的。 数据结构中的栈的…

SVN命令行更新代码

命令列表 svn help查看帮助信息 Available subcommands: add auth blame (praise, annotate, ann) cat changeli…

[转载] Java中Runtime的使用

参考链接&#xff1a; Java中的JVM的关闭挂钩 1 JDK中Runtime的定义 http://blog.csdn.net/lysnow_oss/archive/2007/05/12/1606349.aspx <转载> 那就首先说点Runtime类吧&#xff0c;他是一个与JVM运行时环境有关的类&#xff0c;这个类是Singleton的。我…

窄带物联网(NB-IoT)初步了解

哪有什么天生如此&#xff0c;只是我们天天坚持。既然总有人要赢的话&#xff0c;为什么不能是我呢&#xff1f;[TOC] 什么是NB-Iot? 基于蜂窝的窄带物联网&#xff08;Narrow Band Internet of Things, NB-IoT&#xff09;成为万物互联网络的一个重要分支。NB-IoT构建于蜂窝网…

ai人工智能_人工智能能力问答中的人工智能不确定性

ai人工智能1) Which of the following is true with respect to uncertainty in AI systems? Uncertainty arises when we are not 100 percent confident in our decisionsWhenever uncertainty arises, there is needs to be an estimation taken for getting to any conclu…

[转载] 弄懂JDK、JRE和JVM到底是什么

参考链接&#xff1a; JDK JRE和JVM之间的区别 首先是JDK JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。 在JDK的安装目录下有一个jre目录&#xff0c;里面有两个文件夹bin和lib&#xff0c;在这里可以认为bin里的就是jvm&#xff0c;lib中则是jvm工作所需要…

mcq 队列_人工智能搜索问题能力问题解答(MCQ)

mcq 队列1) The main Aim of the AI system is to provide a solution for real-life problems by acting and thinking humanly. Whenever an agent is confronted by a problem, what is the first step that it follows towards searching a solution to the problem? Sear…

JavaOne大事纪:IBM谈OpenJ9和Open Liberty

JavaOne大会以IBM陈述其最近对开源社区的贡献作为开场&#xff1a;OpenJ9、Open Liberty和MicroProfile。IBM杰出工程师John Duimovich做了“IBM和Java&#xff1a;助力下一代创新”的开场演讲。\\读者可以回看演讲视频。\\Duimovich说IBM之所以致力于推动Java生态系统的创新&a…

[转载] JVM中对象的回收过程

参考链接&#xff1a; JVM是否创建Main类(具有main()的类)的对象 当我们的程序开启运行之后就&#xff0c;就会在我们的java堆中不断的产生新的对象&#xff0c;而这是需要占用我们的存储空间的&#xff0c;因为创建一个新的对象需要分配对应的内存空间&#xff0c;显然我的内…

c语言格式对齐填充_C ++中类的大小 课堂上的填充和对齐| 派生类的大小

c语言格式对齐填充Prerequisite: 先决条件&#xff1a; sizeof() operator in C/C C / C 中的sizeof()运算符 Size of struct in C C中的struct大小 We know that a struct size is not only the summation of all the data members, rather its the minimum sum guaranteed. …

ELK系列~对fluentd参数的理解

这段时候一直在研究ELK框架&#xff0c;主要集成在对fluentd和nxlog的研究上&#xff0c;国内文章不多&#xff0c;主要看了一下官方的API&#xff0c;配合自己的理解&#xff0c;总结了一下&#xff0c;希望可以帮到刚入行的朋友们&#xff01; Fluentd&#xff08;日志收集与…

[转载] Java中的50个关键字

参考链接&#xff1a; Java平台如何独立 Java中的50个关键字 关键字也称为保留字&#xff0c;是指java语言中规定了特定含义的标示符。对于保留字&#xff0c;用户只能按照系统规定的方式使用&#xff0c;不能自行定义。Java中有50个常用关键字&#xff1a; 与数据类型相关…

MySQL 直接存储图片并在 html 页面中展示,点击下载

数据库实体类&#xff1a; package com.easy.kotlin.picturecrawler.entityimport java.util.* import javax.persistence.*Entity Table(indexes arrayOf(Index(name "idx_url", unique true, columnList "url"),Index(name "idx_category"…

css 文本背景色透明_如何使用CSS将文本或图像的背景设置为透明?

css 文本背景色透明Introduction: 介绍&#xff1a; In web development, there are numerous ways by which we can style our websites or web pages. You can make use of lots of properties for creating attractive and responsive websites. 在Web开发中&#xff0c;我…

[转载] 1.1Java使用JDBC原生方式连接MySql数据库

参考链接&#xff1a; Java数据库连接JDBC驱动程序 前言&#xff1a;今天有朋友问我原生的java连接数据库&#xff0c;因为框架的使用&#xff0c;如果基础不牢固的人&#xff0c;是很容易遗忘原生的连接方式。今天正好趁此做一下回顾&#xff1a; 这里只考虑原生方式&#x…

maven安装及集成myeclipse

第一步&#xff1a;下载和安装 1、官网下载Maven&#xff1a;http://maven.apache.org/download.cgi 2、解压到一个文件夹2、设置环境变量&#xff1a;如&#xff1a;M2_HOME&#xff1a;D:\JAVA\apache-maven-3.0.5在path中添加;%M2_HOME%\bin;第二步&#xff1a;和MyEclipse集…

[转载] Java泛型详解:<T>和Class<T>的使用。泛型类,泛型方法的详细使用实例

参考链接&#xff1a; Java中的main()函数是强制性的吗 一、引入 1、泛型是什么 首先告诉大家ArrayList就是泛型。那ArrayList能完成哪些想不到的功能呢&#xff1f;先看看下面这段代码&#xff1a; [java] view plain copy ArrayList<String> strList new ArrayL…

数字和数字根的总和_使用8086微处理器查找8位数字的数字总和

数字和数字根的总和Problem statement: 问题陈述&#xff1a; Write an assembly language program in 8086 microprocessor to find sum of digit of an 8 bits number using 8 bits operation. 在8086微处理器中编写汇编语言程序&#xff0c;以使用8位运算找到8位数字的位数…

[转载] Java笔试题集锦

参考链接&#xff1a; 关于Java中文件名和类名的误解 Java笔试题集锦 1.MVC的各个部分都有那些技术来实现?如何实现? 答&#xff1a;MVC是Model&#xff0d;View&#xff0d;Controller的简写。"Model" 代表的是应用的业务逻辑&#xff08;通过JavaBean&#xff…