java中JVM中如何存取数据和相关信息详解

  

  

我们每天都在编写Java代码,编译,执行。很多人已经知道Java源代码文件(. Java后缀)会被Java编译器编译为字节码文件(. class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。
  

  

那在整个程序执行过程中,JVM中怎么存取数据和相关信息呢?
  

  

事实上在JVM中是用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为运行时数据区(运行时数据区),也就是我们常说的JVM内存。
  

  

  

 java中JVM中如何存取数据和相关信息详解

  

根据《Java虚拟机规范》的规定,运行时数据区通常包括这几个部分:程序计数器(程序计数器寄存器),Java虚拟机栈(Java虚拟机栈),本地方法栈(本地方法栈),方法区面积(方法),堆(Heap)。
  

  


  

  

<强> 1,程序计数器
  

  

这个内存区域是Java虚拟机规范中唯一一个没有规定任何伯父(OutOfMemoryError)情况的区域,这是这个区域最大的特点之一,这是因为程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象的(OutOfMemory)。
  

  

这个区域主要是负责记录正在执行的虚拟机字节码指令地址,即当前线程执行的字节码的行号指示器(注意:JVM不是直接执行Java代码,而是执行. class文件,所以只要其他编程语言能翻译成. class文件一样能放入JVM中执行)。

  

<强> JVM会给每个线程一个独立的程序计数器,计数器之间互不影响强,且通过线程轮流切换并且分配处理器执行时间来实现JVM的多线程。不过当线程执行的是原生的方法的时候这个计数器中的值为定义。
  

  

<强> 2,Java虚拟机栈
  和程序计数器一样的是Java虚拟机栈是线程私有,生命周期和线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的时候都会创建栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息,每个方法从调用到执行完成的过程,就对应一个栈帧在虚拟机中入栈到出栈的过程,其中64位长度的长和两类型的数据会占用2个局部变量空间,其余的数据类型只占用1个。

  

这里需要理解一下的就是为什么要用栈这个结构呢,比如一方法中调用了B方法,虚拟机中是先让一方法的栈帧进入虚拟机栈执行,当执行到调用B方法的语句就让B栈帧进入,执行完之后B栈帧就出栈,一个栈就继续执行。这里注意的是如果递归的方法递归的太深很容易抛出下面两种异常,所以递归虽然写起来方便,但是性能会有所下降,并且容易抛出异常。
  

  

Java虚拟机规范中,对这个区域规定了两种异常状况
  

  
      <李>线程请求栈的深度大于虚拟机所允许栈的深度,将抛出栈溢出错误李   <李>如果虚拟机栈可以动态扩展且扩展时无法申请到足够的内存,会抛出OutOfMemoryError李   
  

<强> 3,本地方法栈
  

  

与虚拟机栈作用相似,不过是虚拟机栈为虚拟机执行Java方法提供,而本地方法为虚拟机使用到的原生方法服务,本机方法多是用c++写的。抛出的异常和虚拟机栈相同。

  

<强> 4,Java堆
  

  

Java堆是与前面的区域不同的是:这个区域是被所有线程共享的一块内存区域,用来存放对象实例,并为对象实例分配好内存. Java虚拟机规范中这样描述:所有对象实例以及数组都要在堆上分配Java堆也是垃圾收集器管理的主要区域,也叫“GC堆”。由于现在的垃圾回收算法多是分代收集,所以Java堆里面又可分为:新生代和老年代,并且根据Java虚拟机规范的规定:Java堆可以处于物理上不连续的内存空间中,只要逻辑上连续即可。有实例没有被分配,且堆无法再扩展的时候会抛出OutOfMemoryError异常,虚拟机调优其实也主要关注的是这个区域。

  

<强> 5,方法区
  

  

与Java堆一样,线程共享,用来存储被虚拟机加载的类信息,常量、静态变量。这个区域Java虚拟机规范对其特别宽松,既可以像Java堆那样不需要连续内存,又可以选择固定大小和可扩展。还可以选择不实现垃圾收集,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载。当无法满足内存分配需求时,将抛出OutOfMemoryError异常。

java中JVM中如何存取数据和相关信息详解