精华内容
下载资源
问答
  • jvm 内存模型

    万次阅读 多人点赞 2019-08-15 14:28:51
    2. jvm 内存模型划分 根据JVM规范,JVM 内存共分为虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。 程序计数器(线程私有): 是当前线程锁执行字节码的行号治时期,每条线程都有一个独立的程序计数器...

    二. jvm 内存模型划分

    根据JVM规范,JVM 内存共分为虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。
    这里写图片描述

    程序计数器(线程私有):
    是当前线程锁执行字节码的行号治时期,每条线程都有一个独立的程序计数器,这类内存也称为“线程私有”的内存。正在执行java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果是Natice方法,则为空。

    java 虚拟机栈
    也是线程私有的。
    每个方法在执行的时候也会创建一个栈帧,存储了局部变量,操作数,动态链接,方法返回地址。
    每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。
    通常所说的栈,一般是指在虚拟机栈中的局部变量部分。
    局部变量所需内存在编译期间完成分配,
    如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。
    如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。
    本地方法栈(线程私有)
    和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。也会抛出StackOverflowError 和OutOfMemoryError。

    Java堆(线程共享)
    被所有线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例。
    对可以按照可扩展来实现(通过-Xmx 和-Xms 来控制)
    当队中没有内存可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。
    方法区(线程共享)
    被所有方法线程共享的一块内存区域。
    用于存储已经被虚拟机加载的类信息,常量,静态变量等。
    这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载。

    3.jvm 1.8 内存区域划分
    这里写图片描述

    程序计数器
    每个线程一块内存,指向当前正在执行的字节码的行号。如果当前线程是native方法,则其值为null。

    ps(程序计数器内存划分)
    因为处理器在一个确定是时刻只会执行一个线程中的指令,线程切换后,是通过计数器来记录执行痕迹的,因而可以看出,程序计数器是每个线程私有的。
    如果执行的是java方法,那么记录的是正在执行的虚拟机字节码指令的地址的地址,如果是native方法,计数器的值为空(undefined)。

    Java虚拟机栈

    这里写图片描述

    ps: 虚拟机栈中的名词解释

    局部变量表:
    存放编译期可知的各种基本数据类型、对象引用类型和returnAddress类型(指向一条字节码指令的地址:函数返回地址)。
    long、double占用两个局部变量控件Slot。
    局部变量表所需的内存空间在编译期确定,当进入一个方法时,方法在栈帧中所需要分配的局部变量控件是完全确定的,不可动态改变大小。
    异常:线程请求的栈帧深度大于虚拟机所允许的深度—StackOverFlowError,如果虚拟机栈可以动态扩展(大部分虚拟机允许动态扩展,也可以设置固定大小的虚拟机栈),但是无法申请到足够的内存—OutOfMemorError。

    操作数栈:
    后进先出LIFO,最大深度由编译期确定。栈帧刚建立使,操作数栈为空,执行方法操作时,操作数栈用于存放JVM从局部变量表复制的常量或者变量,提供提取,及结果入栈,也用于存放调用方法需要的参数及接受方法返回的结果。
    操作数栈可以存放一个jvm中定义的任意数据类型的值。
    在任意时刻,操作数栈都一个固定的栈深度,基本类型除了long、double占用两个深度,其它占用一个深度
    动态连接:
    每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用,一部分会在类加载阶段或第一次使用的时候转化为直接引用(如final、static域等),称为静态解析,另一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

    方法返回地址:
    当一个方法被执行后,有两种方式退出该方法:执行引擎遇到了任意一个方法返回的字节码指令或遇到了异常,并且该异常没有在方法体内得到处理。无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者的PC计数器的值就可以作为返回地址,栈帧中很可能保存了这个计数器值,而方法异常退出时,返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。
    方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,如果有返回值,则把它压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令。


    堆时JVM内存占用最大,管理最复杂的一个区域。唯一的途径就是存放对象实例:所有的对象实例以及数组都在堆上进行分配。jdk1.7以后,字符串常量从永久代中剥离出来,存放在堆中。堆具有进一步的内存划分。按照GC分代手机角度划分
    这里写图片描述
    老年代:2/3的堆空间
    年轻代:1/3的堆空间
    eden区:8/10 的年轻代
    survivor0: 1/10 的年轻代
    survivor1:1/10的年轻代

    元数据区域
    元数据区域取代了1.7版本及以前的永久代。元数据和永久代本质上都时方法区的实现。方法区皴法虚拟机加载的类型西,静态变量,常量数据。
    参数设置:-XX:MetaspaceSize=18m
    -XX:MaxMetaspaceSize=60m
    直接内存
    java.nio 中使用DirectBuffer相关使用(此处未完待续。。。。。。。。。)

    展开全文
  • JVM内存模型

    万次阅读 2020-07-06 15:54:20
    JVM内存模型 JVM的内存模型也就是JVM中的内存布局,不要与java的内存模型(与多线程相关)混淆。 下图是jdk8 jvm内存模型图: 程序计数器 程序计数器是当前线程所执行的字节码的行号指示器。 JVM支持多个线程同时...

    JVM内存模型

    JVM的内存模型也就是JVM中的内存布局,不要与java的内存模型(与多线程相关)混淆。

    下图是jdk8 jvm内存模型图:

    在这里插入图片描述

    程序计数器

    程序计数器是当前线程所执行的字节码的行号指示器。

    JVM支持多个线程同时运行,每个线程都会根据CPU时间片来回切换,那么如果当前线程获得时间片了,怎么知道它目前要执行哪条指令呢,所以需要一个地方记录当前线程所执行的指令行号,这个地方就是程序计数器,每一个线程都有自己私有的程序计数器。

    倘若当前执行的是JVM的方法,则该寄存器中保存当前执行指令的行号;倘若执行的是native方法,则PC寄存器中为空。

    我们可以看一下程序计数器里面的具体内容。找一个class文件,使用javap命令输出对应的字节码,可以发现每个指令前面都有序号,可以认为他们就是程序计数器的内容。

    0 getstatic #2 <java/lang/System.out>
    3 ldc #3 <Hello World>
    5 invokevirtual #4 <java/io/PrintStream.println>
    8 return
    

    此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

    虚拟机栈

    每个线程有一个私有的虚拟机栈,随着线程的创建而创建,随着线程死亡而死亡。每当线程调用一个java方法时,jvm都会在该线程的虚拟机栈中压入一个新的栈帧,当方法调用完成后,对应的栈帧就会出栈,当虚拟机栈中所有的栈帧都出栈后,线程也就结束了。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

    栈帧用于存储局部变量表、操作数栈、动态链接、方法出口(返回地址)等信息。

    在这里插入图片描述

    局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小,方法的参数也是存在局部变量表中。

    操作数栈用来存储方法执行过程中产生的中间变量。

    每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。我们知道Class文件的常量池有存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

    虚拟机栈会有两种异常状况:

    1. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常
    2. 当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常

    本地方法栈

    本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的Native方法服务。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

    Java堆

    Java堆存放对象实例以及数组,可以根据虚拟机参数-Xmx和-Xms来控制堆的大小。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。Java堆中可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间。

    方法区

    方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

    方法区、永久代与元空间:

    • 方法区是JVM的规范,而永久代和元空间是方法区的两种不同的实现。
    • JDK7及以前方法区的实现为永久代,是在堆上分配。
    • JDK8及以后方法区的实现为元空间,是在本地内存上分配。

    元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:

    • -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
    • -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

    JVM中存在多个常量池,比如类文件常量池、字符串常量池。字符串常量池是直接分配在堆上(jdk8以前是永久代),而类文件常量池等是在方法区,也就是元空间。运行时常量池是在类加载后的一个内存区域,也在元空间。

    直接内存

    直接内存不是虚拟机运行时数据区的一部分,直接内存的分配不会受到JVM的限制,但是会受到物理内存的限制,内存不足时出现OutOfMemoryError。

    在JDK1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

    更多精彩内容关注本人公众号:架构师升级之路
    在这里插入图片描述

    展开全文
  • jvm内存模型

    2017-07-03 11:25:01
    jvm内存模型

    jvm内存模型:Java代码是运行在Java虚拟机之上的,由Java虚拟机通过解释执行(解释器)或编译执行(即时编译器)来完成,故Java内存模型,也就是指Java虚拟机的运行时内存模型。运行时内存模型,分为线程私有和共享数据区两大类,其中线程私有的数据区包含程序计数器、虚拟机栈、本地方法区,所有线程共享的数据区包含Java堆、方法区,在方法区内有一个常量池。java运行时的内存模型图,如下:

    作者:Gityuan
    链接:https://www.zhihu.com/question/19748817/answer/88610988
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    http://www.cnblogs.com/dingyingsi/p/3760447.html 深入理解java虚拟机部分

    http://blog.csdn.net/u012387062/article/details/49406447 详细介绍

    展开全文
  • JVM 内存模型

    2021-01-14 15:04:47
    运行时数据区(JVM内存区域) 字节码执行引擎(C++实现) java Math 的执行先由类装载子系统加载Math.class,将数据都放到运行时数据区,最终通过字节码执行引擎来执行程序代码。 JVM 内存模型 运行时数据区 Run-...

    博文目录


    java虚拟机(JVM)在java程序运行的过程中,会将它所管理的内存划分为若干个不同的数据区域,这些区域有的随着JVM的启动而创建,有的随着用户线程的启动和结束而建立和销毁。
    在这里插入图片描述

    JVM虚拟机

    JVM虚拟机的组成有3个部分,其中最重要的就是 运行时数据区

    • 类装载子系统(C++实现)
    • 运行时数据区(JVM内存区域)
    • 字节码执行引擎(C++实现)

    java Math 的执行先由类装载子系统加载Math.class,将数据都放到运行时数据区,最终通过字节码执行引擎来执行程序代码。

    JVM 内存模型 运行时数据区 Run-Time Data Areas

    JDK8下JVM内存模型的组成如下

    • 堆(Heap)
    • 栈(Java Virtual Machine Stacks)
      • 栈帧
    • 本地方法栈:
    • 方法区(Method Area)
      • 运行时常量池(Run-Time Constant Pool)
    • 程序计数器(The pc Register)

    堆和方法区是所有线程共享的,栈、程序计数器和本地方法栈都是每个线程独享的

    堆 Heap

    new出来的对象一般放在堆内,有时也会放在栈内

    栈 Java Virtual Machine Stacks

    02-JVM内存模型:虚拟机栈与本地方法栈

    虚拟机栈是用于描述java方法执行的内存模型。

    官方叫虚拟机栈,个人理解叫线程栈更合适。线程运行前,jvm会给每个线程创建一个独享的线程栈,主要存放该线程运行时的各方法的局部变量。我们常说的“堆内存、栈内存”中的“栈内存”指的便是虚拟机栈。

    方法调用时,创建栈帧,并压入虚拟机栈;方法执行完毕,栈帧出栈并被销毁,释放内存。线程结束后,线程栈销毁,释放内存。

    特点

    虚拟机栈是线程隔离的,即每个线程都有自己独立的虚拟机栈。

    虚拟机栈的StackOverflowError

    若单个线程请求的栈深度大于虚拟机允许的深度,则会抛出StackOverflowError(栈溢出错误)。

    JVM会为每个线程的虚拟机栈分配一定的内存大小(-Xss参数),因此虚拟机栈能够容纳的栈帧数量是有限的,若栈帧不断进栈而不出栈,最终会导致当前线程虚拟机栈的内存空间耗尽,典型如一个无结束条件的递归函数调用。

    虚拟机栈的OutOfMemoryError

    不同于StackOverflowError,OutOfMemoryError指的是当整个虚拟机栈内存耗尽,并且无法再申请到新的内存时抛出的异常。

    JVM未提供设置整个虚拟机栈占用内存的配置参数。虚拟机栈的最大内存大致上等于“JVM进程能占用的最大内存(依赖于具体操作系统) - 最大堆内存 - 最大方法区内存 - 程序计数器内存(可以忽略不计) - JVM进程本身消耗内存”。当虚拟机栈能够使用的最大内存被耗尽后,便会抛出OutOfMemoryError,可以通过不断开启新的线程来模拟这种异常。

    栈帧(Stack Frame)

    栈帧存放于线程栈内。栈内的栈帧是先进后出的。线程启动后,每一个方法调用前,jvm会在该线程栈内压入为该方法创建的独享的一个栈帧,方法内的局部变量都放在该栈帧内,方法结束后栈帧弹出线程栈释放内存。

    举例:程序启动,jvm给主线程分配线程栈,jvm给main方法创建栈帧并压入线程栈,当执行到调用另一个compute方法时,jvm为compute方法创建栈帧并压入线程栈(此时线程栈中有两个栈帧),待compute执行结束,对应栈帧弹出销毁,接着执行main方法中的内容,main方法执行结束后,对应栈帧弹出销毁,线程结束,对应线程栈销毁。

    特别说明,嵌套调用会一直创建栈帧,最后占满栈帧空间,然后报 StackOverFlowError

    栈帧主要包含如下结构

    • 局部变量表
    • 操作数栈
    • 动态链接
    • 方法出口

    局部变量表

    放局部变量的值, 并不会存放局部变脸的符号. 类似数组(table), 索引0代表调用栈帧对应的该方法的对象 this, 索引1及之后代表的都是方法内部的局部变量了. 基本数据类型的局部变量直接把值存在局部变量表中, 引用类型的局部变量会把对象存在堆中, 然后在局部变量表中引用对应的地址

    如 a=1, math=new Math(), 索引1代表a, 索引1对应的值是1, 索引2代表d, 索引2对应的值是存在堆中的Math实例的内存地址

    操作数栈

    在程序运行过程中用于临时存放数据的中转内存空间. 是一个栈, 先进后出

    动态链接

    动态链接的定义是在程序运行期间完成的将符号引用替换为直接引用. 程序启动时, 各种代码会加载到方法区, 每个方法都会有对应的内存地址, 动态链接就是把符号替换为对应的内存地址, 当前栈帧对应的方法的代码的直接地址就放在动态链接这块内存中

    方法出口

    该栈帧对应的方法执行完后, 需要回到调用该方法的代码的地方, 方法出口里面就保存了这些信息

    程序计数器(Program Counter Register)

    01-JVM内存模型:程序计数器

    程序计数器是一个记录着当前线程所执行的字节码的行号指示器。执行java方法时,程序计数器是有值的,且记录的是正在执行的字节码指令的地址。由字节码执行引擎每执行完一行代码后负责修改。作用是cpu轮转后字节码指令能接着运行

    JAVA代码编译后的字节码在未经过JIT(实时编译器)编译前,其执行方式是通过“字节码解释器”进行解释执行。简单的工作原理为解释器读取装载入内存的字节码,按照顺序读取字节码指令。读取一个指令后,将该指令“翻译”成固定的操作,并根据这些操作进行分支、循环、跳转等流程。

    JVM的多线程是通过CPU时间片轮转(即线程轮流切换并分配处理器执行时间)算法来实现的。也就是说,某个线程在执行过程中可能会因为时间片耗尽而被挂起,而另一个线程获取到时间片开始执行。当被挂起的线程重新获取到时间片的时候,它要想从被挂起的地方继续执行,就必须知道它上次执行到哪个位置,在JVM中,通过程序计数器来记录某个线程的字节码执行位置。因此,程序计数器是具备线程隔离的特性,也就是说,每个线程工作时都有属于自己的独立计数器。

    每一条字节码指令都是一个原子操作, 不可分割, cpu时间片耗尽前一定能完成执行完某一条字节码指令

    特点

    1. 线程隔离性,每个线程工作时都有属于自己的独立计数器。
    2. 执行java方法时,程序计数器是有值的,且记录的是正在执行的字节码指令的地址。
    3. 执行native本地方法时,程序计数器的值为空(Undefined)。因为native方法是java通过JNI直接调用本地C/C++库,可以近似的认为native方法相当于C/C++暴露给java的一个接口,java通过调用这个接口从而调用到C/C++方法。由于该方法是通过C/C++而不是java进行实现。那么自然无法产生相应的字节码,并且C/C++执行时的内存分配是由自己语言决定的,而不是由JVM决定的。
    4. 程序计数器占用内存很小,在进行JVM内存计算时,可以忽略不计。
    5. 程序计数器,是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError的区域。

    本地方法栈(Native Method Stack)

    本地方法栈的功能和特点类似于虚拟机栈,均具有线程隔离的特点以及都能抛出StackOverflowError和OutOfMemoryError异常。

    不同的是,**本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是JVM执行的java方法。**如何去服务native方法?native方法使用什么语言实现?怎么组织像栈帧这种为了服务方法的数据结构?虚拟机规范并未给出强制规定,因此不同的虚拟机实可以进行自由实现,我们常用的HotSpot虚拟机选择合并了虚拟机栈和本地方法栈。

    方法区(Method Area)

    常量 + 静态变量 + 类元信息

    常量池(Constant Pool)

    运行时常量池(Run-Time Constant Pool)

    通过 javap -v Math.class 得到的JVM汇编代码中, Constant Pool 中的内容被载入到程序中后都存放在这里

    Constant pool:
       #1 = Methodref          #5.#26         // java/lang/Object."<init>":()V
       #2 = Class              #27            // com/mrathena/Math
       #3 = Methodref          #2.#26         // com/mrathena/Math."<init>":()V
       #4 = Methodref          #2.#28         // com/mrathena/Math.computer:()I
       #5 = Class              #29            // java/lang/Object
       #6 = Utf8               <init>
       #7 = Utf8               ()V
       #8 = Utf8               Code
       #9 = Utf8               LineNumberTable
      #10 = Utf8               LocalVariableTable
      #11 = Utf8               this
      #12 = Utf8               Lcom/mrathena/Math;
      #13 = Utf8               main
      #14 = Utf8               ([Ljava/lang/String;)V
      #15 = Utf8               args
      #16 = Utf8               [Ljava/lang/String;
      #17 = Utf8               math
      #18 = Utf8               computer
      #19 = Utf8               ()I
      #20 = Utf8               a
      #21 = Utf8               I
      #22 = Utf8               b
      #23 = Utf8               c
      #24 = Utf8               SourceFile
      #25 = Utf8               Math.java
      #26 = NameAndType        #6:#7          // "<init>":()V
      #27 = Utf8               com/mrathena/Math
      #28 = NameAndType        #18:#19        // computer:()I
      #29 = Utf8               java/lang/Object
    

    8大数据类型对象池

    String常量池

    字节码 指令码

    JVM 汇编指令 栈和局部变量操作

    将 Math.class 反编译为 jvm汇编指令码(非常规汇编语言),javap -c Math.class -> Math.txt, javap -v Math.class -> Math.txt

    javap -c Math.class -> Math.txt

    Compiled from "Math.java"
    public class com.mrathena.Math {
      public com.mrathena.Math();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: new           #2                  // class com/mrathena/Math
           3: dup
           4: invokespecial #3                  // Method "<init>":()V
           7: astore_1
           8: aload_1
           9: invokevirtual #4                  // Method computer:()I
          12: pop
          13: return
    
      public int computer();
        Code:
           0: iconst_1
           1: istore_1
           2: iconst_2
           3: istore_2
           4: iload_1
           5: iload_2
           6: iadd
           7: bipush        10
           9: imul
          10: istore_3
          11: iload_3
          12: ireturn
    }
    

    javap -v Math.class -> Math.txt

    Classfile /C:/mrathena/develop/workspace/idea/mrathena/test/target/classes/com/mrathena/Math.class
      Last modified 2021-1-15; size 578 bytes
      MD5 checksum 4bd311478d52edaf713c7a8df7f83d12
      Compiled from "Math.java"
    public class com.mrathena.Math
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #5.#26         // java/lang/Object."<init>":()V
       #2 = Class              #27            // com/mrathena/Math
       #3 = Methodref          #2.#26         // com/mrathena/Math."<init>":()V
       #4 = Methodref          #2.#28         // com/mrathena/Math.computer:()I
       #5 = Class              #29            // java/lang/Object
       #6 = Utf8               <init>
       #7 = Utf8               ()V
       #8 = Utf8               Code
       #9 = Utf8               LineNumberTable
      #10 = Utf8               LocalVariableTable
      #11 = Utf8               this
      #12 = Utf8               Lcom/mrathena/Math;
      #13 = Utf8               main
      #14 = Utf8               ([Ljava/lang/String;)V
      #15 = Utf8               args
      #16 = Utf8               [Ljava/lang/String;
      #17 = Utf8               math
      #18 = Utf8               computer
      #19 = Utf8               ()I
      #20 = Utf8               a
      #21 = Utf8               I
      #22 = Utf8               b
      #23 = Utf8               c
      #24 = Utf8               SourceFile
      #25 = Utf8               Math.java
      #26 = NameAndType        #6:#7          // "<init>":()V
      #27 = Utf8               com/mrathena/Math
      #28 = NameAndType        #18:#19        // computer:()I
      #29 = Utf8               java/lang/Object
    {
      public com.mrathena.Math();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."<init>":()V
             4: return
          LineNumberTable:
            line 3: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   Lcom/mrathena/Math;
    
      public static void main(java.lang.String[]);
        descriptor: ([Ljava/lang/String;)V
        flags: ACC_PUBLIC, ACC_STATIC
        Code:
          stack=2, locals=2, args_size=1
             0: new           #2                  // class com/mrathena/Math
             3: dup
             4: invokespecial #3                  // Method "<init>":()V
             7: astore_1
             8: aload_1
             9: invokevirtual #4                  // Method computer:()I
            12: pop
            13: return
          LineNumberTable:
            line 6: 0
            line 7: 8
            line 8: 13
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      14     0  args   [Ljava/lang/String;
                8       6     1  math   Lcom/mrathena/Math;
    
      public int computer();
        descriptor: ()I
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=4, args_size=1
             0: iconst_1
             1: istore_1
             2: iconst_2
             3: istore_2
             4: iload_1
             5: iload_2
             6: iadd
             7: bipush        10
             9: imul
            10: istore_3
            11: iload_3
            12: ireturn
          LineNumberTable:
            line 11: 0
            line 12: 2
            line 13: 4
            line 14: 11
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      13     0  this   Lcom/mrathena/Math;
                2      11     1     a   I
                4       9     2     b   I
               11       2     3     c   I
    }
    SourceFile: "Math.java"
    

    computer 简单方法说明

    # java code
    public int compute() {
    	int a = 1;
    	int b = 2;
    	int c = (a + b) * 10;
    	return c;
    }
    
    # javap -c Math.class
    # javap -v Math.class, -v比-c更详细, 常量池也会有
    public int compute();
    	Code:
    	   0: iconst_1		// 将int类型常量1压入操作数栈, 操作数栈是栈帧里面的主要部分之一, 在操作数栈里压入一个int类型的1
    	   1: istore_1		// 将int类型值存入局部变量1, 局部变量1是a, 将int1从操作数栈中出栈, 将a=1放入局部变量表索引1的位置的内存中
    	   2: iconst_2		// 将int类型常量2压入操作数栈
    	   3: istore_2		// 将int类型值存入局部变量2, 局部变量2是b, 将int2从操作数栈中出栈, 将b=2放入局部变量表索引2的位置的内存中
    	   4: iload_1		// 从局部变量1中装载int类型值, 从局部变量表索引1的位置加载其值, 即加载a的值, 并入栈到操作数栈
    	   5: iload_2		// 从局部变量2中装载int类型值, 入栈到操作数栈, 此时操作数栈中有两个值, 分别是2和1
    	   6: iadd			// 执行int类型的加法, 从操作数栈中出栈2和1, 做加法操作, 将int结果3压入操作数栈
    	   7: bipush	10	// 将一个8位带符号整数压入栈, 即把int的10压入操作数栈, 此时操作数栈中有两个值, 分别是10和3. 这里7->9是因为后面的10也需要占一个内存, 这个内存地址的编号就是8
    	   9: imul			// 执行int类型的乘法, 从操作数栈中出栈10和3, 做乘法操作, 将int结果30压入操作数栈
    	  10: istroe_3		// 将int类型值存入局部变量3, 局部变量3是c, 将int30从操作数栈中出栈, 将c=30放入局部变量表索引3的位置的内存中
    	  11: iload_3		// 从局部变量3中装载int类型值, 从局部变量表索引3的位置加载其值, 即加载c的值, 并入栈到操作数栈
    	  12: ireturn		// 从方法中返回int类型的数据, 将int30从操作数栈中出栈, 并将值返回到主线程
    
    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,149
精华内容 5,659
关键字:

jvm内存模型