jvm内存模型和内存分配

一、什么是jvm?
  • jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的。
  • jvm包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和一个存储方法域。
  • JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
    JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
二、jdk、jre、jvm是什么关系?
  • JRE(Java Runtime Environment),也就是java平台。所有的java程序都要在JRE环境下才能运行。
  • JDK(Java Development Kit),是开发者用来编译、调试程序用的开发包。JDK也是JAVA程序需要在JRE上运行。
  • JVM(Java Virtual Machine),是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
    JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
  • Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。
三、JVM原理
  • jvm是java的核心和基础,在java编译器和os平台之间的虚拟处理器,可在上面执行字节码程序。
  • java编译器只要面向jvm,生成jvm能理解的字节码文件。java源文件经编译成字节码程序,通过jvm将每条指令翻译成不同的机器码,通过特定平台运行。


     
     
四、JVM执行程序的过程
  • 加载.class文件
  • 管理并分配内存
  • 执行垃圾收集

JRE(java运行时环境)由JVM构造的java程序的运行环境,也是Java程序运行的环境,但是他同时一个操作系统的一个应用程序一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。
JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机。

  • 操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境:
  1. 创建JVM装载环境和配置
  2. 装载JVM.dll
  3. 初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例
  4. 调用JNIEnv实例装载并处理class类。
五、JVM的生命周期
  • JVM实例对应了一个独立运行的java程序它是进程级别
    a) 启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void
    main(String[] args)函数的class都可以作为JVM实例运行的起点
    b) 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以表明自己创建的线程是守护线程
    c) 消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出
  • JVM执行引擎实例则对应了属于用户运行程序的线程它是线程级别的
六、JVM内存模型
  • java代码具体执行过程如下图


     
     
  • 运行时数据区,即jvm内存结构图如下图


     
     
  • 运行时数据区存储了哪些数据?
  1. 程序计数器(PC寄存器)
    由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的。由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。
  2. java栈
    Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中 包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。


     
     
  3. 本地方法栈
    本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。

  4. Java中的堆是用来存储对象本身的以及数组(数组引用是存放在Java栈中的)。堆是被所有线程共享的,在JVM中只有一个堆。
  5. 方法区
    与堆一样,是被线程共享的区域。在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
    在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。
    在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。
 
原文地址:https://www.cnblogs.com/hericwan/p/12401087.html