jvm内存结构

80 阅读4分钟

代码执行流程

jvm内存结构,就需要我们结合图来分析,接下来我们会有一个内存结构图,和一份简单的Java源代码。来进行代码执行的分析,和jvm内存结构的分析。

首先在右上角,是一份Java源文件,对应Java Source,此时的java是源代码,并不能被jvm所解析执行,要经过javac 命令把源文件编译成 class文件,此时的class文件才能被jvm执行。此时我们通过java命令来执行class文件。在我们使用java命令执行class文件时,底层就会帮我们创建一个java虚拟机。对class文件进行执行。 在包括,类加载子系统之后的结构都是包括在虚拟机中的结构。

1.类加载

然后jvm会在虚拟机栈中创建一个main线程,由此可以看出,线程的创建是放入栈中。那么main线程 就要去执行main()方法,此时main()方法所对应的Main类,还并没有加载,这时就会通过类加载子系统 对class文件进行类的加载,这些类的基本信息类中的静态变量常量jit即使编译器所编译的热点代码,都将会储存在方法区中,类的基本信息就包括,类的名字啊,有哪些成员,有哪些方法等。

注:在1.7之后的版本呢,静态变量并没有随着类信息存在方法区,也就是元空间。在类加载后,会随之在堆中生成class对象,而静态变量就存储在class对象的尾部。

这里可能还是有很多人可能不知道,方法区到底存储什么,我们就具体列出来

  • 类的基本信息
    • 每个类的全限定名
    • 每个类的直接超类的全限定名
    • 该类是类还是接口
    • 该类的访问修饰符
    • 任何直接超接口的的全限定名的有序列表
  • 字段信息
    • 字段名称
    • 字段类型
    • 字段修饰符
  • 方法信息
    • 方法名
    • 方法返回类型
    • 方法修饰符
    • 方法参数个数,参数类型等
  • 运行时常量池
    • 直接引用
      • 符号引用转化为真实地址
    • 字面量
      • 字符串常量啊,final修饰的,数量值
  • 到类classloader的引用
    • 到该类的类装载器的引用
  • 到类class 的引用
    • 虚拟机为每一个被装载的类型创建一个class实例,用来代表这个被装载的类。

2.执行main方法

类加载后,就可以执行main方法了,这时main线程中就压入了一个栈帧,一个栈帧就是一个方法。遇到Student类,发现方法区没有对应的类,重复第一个步骤,进行类加载,然后 stu 局部变量,将放在该栈帧中的局部变量表中。最后new Student类。在堆中创建一个Student实例。引用地址赋给stu。调用study方法,会再加一个栈帧,进行压栈操作。再调用hashCode()方法,由于hashcode方法是本地方法(native),所以这时后,需要引用本地方法栈中的方法进行调用。

3.垃圾回收

当把stu置成null时,此时student对象,并没有被引用,当发生垃圾回收时,会回收掉student对象。

4.解释器,和 JIT即时编译器

cpu并不能直接执行class文件,所以需要用解释器,将字节码文件,翻译成机器指令,才能让cpu进行读取。 解释器是一句一句进行翻译,十分耗性能。所以当有处代码,一直反复的进行执行,会变成热点代码。及时编译器,就会将该代码优化成机器码,下次再执行该代码时,就直接读机器码,就不用再进行解释。

5.程序计数器

这个差点忘了,因为虚拟机栈中,不会只有一个线程,当多个线程并发执行时,总会有线程没有分到时间片,此时,需要将执行到哪儿记录在程序技术器上,方便下次再分到时间片,cpu知道从何开始。

哪些区域会有内存溢出问题

内存溢出一般会报两种异常。

一个是:OutOfMemoryError

这个异常引起,主要有以下几个点。

  • 当创建的对象达到一定数量时,切都不能被gc,那么堆内存就会溢出。从而导致异常。
  • 当有许多的类加载到方法区中,方法区也会发生内存溢出。
  • 当虚拟机栈中,创建了许多的线程。进而导致虚拟机栈内存溢出。

一个是:StackOverFlowError

这个异常就是当,在该线程中不断地反复的掉大量的方法,从而导致,栈内部内存溢出。

本文使用 文章同步助手 同步