星@语的博客




李白《侠客行》 银鞍照白马,飒沓如流星。十步杀一人,千里不留行。事了拂衣去,深藏身与名。

JVM 基础

JVM

(1)基本概念

  jvm是运行在操作系统上可运行java代码的虚拟计算机,它包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收、堆和一个存储方法域。

(2)运行的过程

  1.java代码-->编译器-->.class字节码文件

  2.字节码文件-->JVM-->机器码

  每个操作系统平台的解释器不同,但JVM虚拟机是相同的,这也是java能跨平台的原因。当一个程序开始运行,虚拟机开始实例化,多个程序启动

会存在多个虚拟机。程序退出和关闭,虚拟机实例消亡,虚拟机实例之间数据不能共享。

   JVM允许一个程序并发执行多个线程。hotspot JVM(JVM是虚拟机的规范,HotSpot是jvm的具体实现)中的Java线程与原生操作系统的线程是直接映射关系。

当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备以后,就会创建一个操作系统原生线程。Java线程结束,原生线程随之被回收。操作系统负责调度

所有线程,并分配到可用的cup上。原生线程初始化完毕后,就会调用Java线程的run方法。线程结束,就会释放原生线程和Java的线程的所有资源。

 

                                            

 

 hotspot JVM 后台运行的系统线程主要有以下几个:

  虚拟机线程:这种线程的操作需要JVM达到安全点才出现,这些操作必须在不同线程中发生的原因是他们都需要JVM达到安全点,这样堆才不会变化。

这种线程的执行类型包括“stop-the-world”的垃圾收集、线程栈收集、线程挂起以及偏向锁撤销。

  周期任务线程:这种线程是周期事件的体现(比如中断),他们一般用于周期性操作的调度执行。

  GC线程:这种线程对在JVM里不同种类的垃圾收集行为提供支持。

  编译线程:在运行时会将字节码编译成机器码。

  信号调度线程:这种线程接收信号并发给JVM,在它内部通过调用适当JVM方法进行处理。

 

JVM 内存区域

     

 

  JVM 内存区域主要分为私有区域【程序计数器、虚拟机栈、本地方法栈】,共享区域【Java堆、方法区】、直接内存。(见图【来自csdn】)

 

       

 

  程序计数器(线程私有)

   这是一块比较小的内存空间(在虚拟机中没有任何的OutOfMemoryError的区域),是当前线程所执行的字节码的行号指示器,每个线程都有一个独立的

程序计数器,这类内存称为”线程私有“的内存。执行Java方法的话,计数器记录的就是虚拟机字节码指令的地址(当前指令的地址),如果是Native方法,则为空。

  虚拟机栈(线程私有)

  是描述Java方法执行的内存模型,Java方法执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个

方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入出栈的过程。

  栈帧(Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态连接(Dynamic Linking)、方法返回值和异常分派(Dispatch Exception)。栈帧

随着方法调用而创建,随着方法结束而摧毁------无论方法是正常完成还是异常完成(抛出了在方法内为被捕获的异常)都算作方法结束。

 

                                             

 

  本地方法区(线程私有)

  本地方法区和Java虚拟机栈作用类似,区别是虚拟机栈是为执行Java方法服务,而本地方法栈则为Native方法(C或C++编写的方法,一般用来调用底层硬件)服务,HotSpot JVM

直接把本地方法栈和虚拟机栈合二为一。

  堆(Heap-线程共享)- 运行时数据区

  该区域是线程共享的,创建的对象和数组都保存在Java堆内存中,也是垃圾收集器进行垃圾收集的重要的内存区域。新一代的JVM采用分代收集算法,因此Java堆从GC角度可以细分为

新生代(Eden区、SurvivorFrom区和 SurvivorTo区)和老年代

 

                                     

 

   新生代:用来存放新生的对象,大概占据堆的1/3空间。由于频繁创建对象,所以新生代会频繁的触发MinorGC进行垃圾回收。新生代又分为Eden区、SurvivorFrom区 、SurvivorTo区。

    Eden区:java新对象的出生地,占新生代内存的8/10(如果新创建的对象占用内存很大,则直接分配到老年代),如果Eden区的内存不够时就会接触MinorGC,对新生代区进行一次垃圾回收。

    SurvivorFrom区:占新生代内存的1/10,上一次MinorGC幸存者,作为这次MinorGC的被扫描者。

    SurvivorTo区:占新生代内存的1/10,MinnorGC扫描SurvivorFrom区之后的幸存者,大部分是还有引用的对象。

  老年代:大概占堆内存的2/3,主要存放应用程序中生命周期比较长的内存对象。老年代的对象比较稳定,MajorGC不会频繁的执行。在进行MajorGC之前一般都要先进行一次MinorGC,新生代的对象

      进入老年代,只有老年代的空间不足时才会触发。不能找到足够大的连续空间分配给新创建的大对象时也会触发一次MajorGC进行垃圾回收。

 

  方法区/永久代(线程共享)

  方法区/永久代用于存储被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。HotSpot JVM把GC分代收集扩展至方法区(和Java堆一样管理这部分内存),方法区/永久代

的内存回收的主要目标是针对常量池的回收类型的卸载

  运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期

生成的各种字面量和符号引用,这部分内容在类加载后存放到方法区的运行时常量池中。

  JAVA8和元数据

  在Java8中,永久代被移除,被“元数据区”(元空间)所取代。元空间的本质和永久代类似,它俩的最大区别:元空间并不在虚拟机中,而是使用本地内存(即元空间内存受本地内存限制)。类的

元数据放入本地内存中,字符串池和类的静态变量放入Java的堆中。

posted @ 2021-07-08 00:00  星_语  阅读(61)  评论(0编辑  收藏  举报