###如图:一 JVM结构及各个组件原理

  • 类加载器

      类加载器(Class loader)负责把class文件加载进运行时数据区。
    类加载器有三种:
     1.启动类加载器(Bootstrap), $JAVAHOME/jre/lib/rt.jar
     2.扩展类加载器(Extension), $JAVAHOME/jre/lib/ext/*.jar
     3.应用程序类加载器(AppClassLoader);
    它们遵循双亲委派机制。当一个类收到了类加载请求,会把请求委派给父类加载,每一个层次类加载器都是如此,只有当父类加载器反馈不能加载时(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。这样就保证了使用不同的类加载器最终得到的都是同一对象。

  • 运行时数据空间

      由五部分组成:程序计数器、本地方法栈、栈、堆、方法区。其中堆和方法区是线程共享的,其他是线程独享、

  • 程序计数器

      程序计数器就是一条指针,指向方法区的方法字节码,由执行引擎(Execution Engine)读取下一条指令。执行引擎负责解释命令,提交操作系统执行。

  • 本地方法栈

      本地方法栈(Native method stack)会调用本地接口(Native Interface)实现线程的创建。

  • 栈内存

      栈主管Java程序的运行,在线程创建时创建,生命期是跟随线程的生命期,线程结束栈内存也就释放。
    栈主要保存三类数据:
     1.本地变量(Local Variables): 输入参数和输出参数以及方法内的变量(8种基本数据类型+对象的引用变量)
     2.栈操作(Operand Stack): 记录出栈、入栈的操作
     3.栈帧数据(Frame Data): 包括类文件、实例方法等
    栈运行遵循“先进后出”原则。
    栈的大小和具体JVM的实现有关,通常在256K~756K之间。
    常见异常:
    java.lang.StackOverflowError
     (1)栈的小格子不够了,不是因为内存溢出!
     (2)调用了太多的方法,导致栈溢出。比如死循环递归调用。

  • 堆内存

      堆存储对象的实例。堆分为新生代和老年代。Hot Spot JVM把年轻代分为了三部分,一个Eden和两个survivor(From和To),默认是8:1:1。Survivor 区相当于是 Eden 区和 Old 区的一个缓冲,设置两个 Survivor 区最大的好处就是解决内存碎片化。
    常见异常:
    java.lang.OutOfMemoryError: Java heap space
     (1)Java虚拟机的堆内存设置不够,可以通过参数-Xms、-Xmx来调整。
     (2)代码中创建了大量大对象,并且长时间不能被垃圾收集器收集。

  • 方法区

      存储静态变量、常量、类结构(构造方法/接口定义)、运行时常量池。
    运行时常量池:虚拟机会将各个class文件中的常量池载入到运行时常量池中,即编译期间生成的字面量、符号引用,总之就是装载class文件。
    方法区是Java虚拟机规范中的定义,是一种规范。
    对于Java8,元空间(MateSpace)是方法区的实现,元空间并不在虚拟机中而是使用本机物理内存。
    但静态变量和常量池并不存入元空间,而是存储在堆中。
    字符串常量池也储存在堆中。

栈、堆、方法区的交互关系

  栈中的引用对象指向堆内存中对象的实例数据,堆内存实例数据是根据方法区类结构产生。

相关文章:

  • 2021-10-08
  • 2021-10-05
  • 2021-06-09
  • 2021-12-04
  • 2021-05-23
  • 2021-09-05
  • 2021-05-23
猜你喜欢
  • 2021-06-09
  • 2021-05-27
  • 2021-06-09
  • 2021-08-08
  • 2021-07-16
  • 2021-06-23
  • 2021-10-14
相关资源
相似解决方案