美文网首页
三、JVM系列(Java虚拟机内存结构)

三、JVM系列(Java虚拟机内存结构)

作者: 大虾啊啊啊 | 来源:发表于2021-05-06 09:54 被阅读0次

    前言

    在之前我们知道,Java源文件通过JavaC编译器编译成了字节码文件(.class文件),接下来我们就要让Java虚拟机运行字节码文件,从而得到我们最终想要的结果。在这个过程,Java虚拟机会载入字节码文件,将其存入Java虚拟机的内存空间中。
    那么字节码数据在Java虚拟机中是如何存放的呢?Java虚拟机在为类实例、成员变量分配内存是如何分配的呢?带着这些问题,我们先来了解一下Java虚拟机的内存结构。

    Java虚拟机内存结构(Java虚拟机规范中也称之为运行时数据区)

    Java虚拟机内存结构可以分为线程公有和线程私有的两部分:

    • 公有部分
      公有部分指的是所有线程都共享的部分,包含了Java堆、方法区、常量池。
    • 私有部分
      私有部分指的是每个线程私有的数据,包含了PC寄存器、Java虚拟机栈、本地方法栈。

    1、公有部分:Java堆、方法区、常量池

    • Java堆是从JVM划分出来的一块区域,这块区域专门用于Java实例对象的分配,几乎所有的对象都会在这里进行内存分配,也就是说几乎所有的实例对象都存储在Java堆中。(有些时候小对象会直接在栈上进行分配,暂不介绍)
    • 方法区是存储Java类字节码数据的一块区域,它存储了每一个类的结构信息,比如运行时常量池、字段、方法数据、构造方法等。这里我们知道常量池是存储在方法区中的。
      Java堆我们知道是用来存储实例对象的,并且Java堆根据对象存活时间的不同还分为了年轻代、老年代两个区域。而年轻代还被进一步划分成了Eden区、From Survivor0区、To Survivor1区。如图:


      image.png

      当有对象需要内存分配的时候,优先分配到了年轻代的Eden区。等到Eden区内存不足的时候,Java虚拟机会启动垃圾回收,此时Eden区没有被引用的对象占用的内存就会被回收。而一些存活比较久的对象则会进入到老年代。在Java虚拟机中有一个名为-XX:MaxTenuringThreshold 的参数专门用来统计一个对象从年轻代进入到老年代需要GC的次数。即年轻代对象GC指定次数后,下一次GC就会进入到老年代。
      为什么Java堆要这样划分区域呢?
      在虚拟中中必然有存活时间短的对象,也有存活时间较长的对象。如果我们将其混在一起,那么因为存活较短的对象有很多势必会导致频繁垃圾回收。而垃圾回收不得不对所有的内存都进行扫描,那么其实有一部分对象存活时间较长,对他们进行扫描完全是浪费时间。因此为了提高回收的效率,就进行了分区。

    2、私有部分:PC寄存器、Java 虚拟机栈、本地方法栈

    以上我们知道Java堆和方法区方法区是线程公有的内存部分。而Java虚拟机内存中也有一部分是线程私有的。他们包括了:PC寄存器、Java虚拟机栈、本地方法栈。

    • PC寄存器
      指的是保存线程当前执行的方法。任意时刻,一条Java虚拟机线程只会执行一个方法的代码。而这个被线程执行的方法称为该线程的当前方法,其地址存在PC寄存器中。
    • Java虚拟机栈
      这个栈与线程同时创建。用来存储栈帧,即存储局部变量、与一些过程结果的地方。
    • 本地方法栈
      当Java虚拟机使用其他语言(C语言)来实现指令集解释器的时候,会使用带本地方法栈(用的比较少)

    小结

    学到这里我们就知道一个Java文件经过JavaC编译器编译成了字节码文件,然后字节码载入Java虚拟机内存。我们的类的信息就会存在方法区中。如果创建对象,那么我们的对象就会存在Java堆中。如果调用方法,就会用到PC寄存器、Java虚拟机栈、本地方法栈。面对如此多的Java类,Jvm是如何决定这些类的加载顺序呢?又是如何控制他们的加载呢?下一节我们讲讲JVM的类加载机制。

    相关文章

      网友评论

          本文标题:三、JVM系列(Java虚拟机内存结构)

          本文链接:https://www.haomeiwen.com/subject/hiprdltx.html