加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 空间 > 正文

对JVM还有什么不懂的?带你深入浅出JVM!

发布时间:2019-10-14 13:06:13 所属栏目:空间 来源:java互联网架构
导读:副标题#e# JVM JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数据区域(runtime data area) 下面这幅图展示了一个典型的JVM(符合JVM Specification Java SE 7 Edition)所具备的关键内部组件。 组件中的多线程处理 多线程处理或自由线

若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)

非堆式内存

有些对象并不会创建在堆中,这些对象在逻辑上被认为是JVM机制的一部分。

非堆式的内存包括:

  • 永久代中包含:
  • 方法区
  • 内部字符串
  • 代码缓存:用于编译以及存储方法,这些方法已经被JIT编译成本地代码

内存管理

对象和数组永远都不会被显式释放,因此只能依靠垃圾回收器来自动地回收它们。

通常,以如下的步骤进行:

  1. 新对象和数组被创建在年轻代
  2. 次垃圾回收器将在年轻代上执行。那些仍然存活着的对象,将被从eden区移动到survivor区
  3. 主垃圾回收器将会把对象在代与代之间进行移动,主垃圾回收器通常会导致应用程序的线程暂停。那些仍然存活着的对象将被从年轻代移动到老年代
  4. 永久代会在每次老年代被回收的时候同时进行,它们在两者中其一满了之后都会被回收

JIT编译

JIT具体的做法是这样的:当载入一个类型时,CLR为该类型创建一个内部数据结构和相应的函数,当函数第一被调用时,JIT将该函数编译成机器语言.当再次遇到该函数时则直接从cache中执行已编译好的机器语言.

方法区

所有的线程共享相同的方法区。所以,对于方法区数据的访问以及对动态链接的处理必须是线程安全的。如果两个线程企图访问一个还没有被载入的类(该类必须只能被加载一次)的字段或者方法,直到该类被加载完成,这两个线程才能继续执行。

类的文件结构

一个被编译过的类文件包含如下的结构:

  1. ClassFile 
  2.  { u4magic; u2minor_version; u2major_version; u2constant_pool_count;  
  3. cp_infocontant_pool[constant_pool_count – 1]; u2access_flags;  
  4. u2this_class; u2super_class; u2interfaces_count;  
  5. u2interfaces[interfaces_count]; u2fields_count;  
  6. field_infofields[fields_count]; u2methods_count;  
  7. method_infomethods[methods_count]; u2attributes_count;  
  8. attribute_infoattributes[attributes_count];} 
对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

可以使用javap命令查看被编译后的java类的字节码。

下面列出了在该类文件中,使用到的操作码:

对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

就像在其他通用的字节码中那样,以上这些操作码主要用于跟本地变量、操作数栈以及运行时常量池打交道。

构造器有两个指令,第一个将“this”压入到操作数栈,接下来该构造器的父构造器被执行,这一操作将导致this被“消费”,因此this将从操作数栈出栈。

对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

而对于sayHello()方法,它的执行将更为复杂。因为它不得不通过运行时常量池,解析符号引用到真实的引用。第一个操作数getstatic,用来入栈一个指向System类的静态字段out的引用到操作数栈。接下来的操作数ldc,入栈一个字符串字面量“Hello”到操作数栈。最后,invokevirtual操作数,执行System.out的println方法,这将使得“Hello”作为一个参数从操作数栈出栈,并为当前线程创建一个新的frame。

对JVM还有什么不懂的?资深架构师一篇文章带你深入浅出JVM!

以及高并发,分布式,spring源码,mybatis源码,大数据,Netty等多个技术知识点全面讲解的架构视频资料

类加载器

JVM的启动是通过bootstrap类加载器来加载一个用于初始化的类。在publicstatic void main(String[])被执行前,该类会被链接以及实例化。main方法的执行,将顺序经历加载,链接,以及对额外必要的类跟接口的初始化。

加载: 加载是这样一个过程:查找表示该类或接口类型的类文件,并把它读到一个字节数组中。接着,这些字节会被解析以确认它们是否表示一个Class对象以及是否有正确的主、次版本号。任何被当做直接superclass的类或接口也一同被加载。一旦这些工作完成,一个类或接口对象将会从二进制表示中创建。

链接: 链接包含了对该类或接口的验证,准备类型以及该类的直接父类跟父接口。简而言之,链接包含三个步骤:验证、准备以及解析(optional)

验证:该阶段会确认类以及接口的表示形式在结构上的正确性,同时满足Java编程语言以及JVM语义上的要求。

在验证阶段执行这些检查意味着在运行时可以免去在链接阶段进行这些动作,虽然拖慢了类的加载速度,然而它避免了在执行字节码的时候执行这些检查。

准备:包含了对静态存储的内存分配以及JVM所使用的任何数据结构(比如方法表)。静态字段都被创建以及实例化为它们的默认值。然而,没有任何实例化器或代码在这个阶段被执行,因为这些任务将会发生在实例化阶段。

解析:是一个可选的阶段。该阶段通过加载引用的类或接口来检查符号引用是否正确。如果在这个点这些检查没发生,那么对符号引用的解析会被推迟到直到它们被字节码指令使用之前。

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读