Java虚拟机内存结构

当Java虚拟机运行一个程序时,它需要内存空间来存储许多东西,如字节码,创建的对象,传递给方法的参数,方法中定义的临时变量,方法的返回值等。Java虚拟机通通把

这些数据放到“运行时数据区”中以便于管理。

Java虚拟机内存结构_第1张图片

如图虚线范围内所示,Java虚拟机一般包括这几块存储区域:方法区,堆区,Java栈,PC寄存器和本地方法栈。这几块存储区分别存储不太能够的数据信息,各司其职,共同组成了虚拟机的“运行时数据区”,下面我们将分别介绍这几块区域。

  • 方法区  Java虚拟机需要装载一个类型信息时,它首先定位到相应的class文件,然后读入该class文件——一个线性的二进制流,最后虚拟机从二进制流中提取出类型信息,并将这些类型信息保存到方法区中;另外,类变量(静态变量)也保存在方法区中。方法区是所有线程共享的,也即是说,对于一个Java虚拟机,方法区在逻辑上只有一个,当然物理上方法区可以是不连续的内存空间。
  • 堆区  Java程序运行时创建的实例都存储在堆区,同方法区一样,一个Java虚拟机也只有一个堆区,堆区在逻辑上也只有一个,并且可以是不连续的内存空间。Java虚拟机中有一个在堆区分配内存的指令,但是没有在堆区释放内存的指令,虚拟机自己决定什么时候回收堆区中的内存空间,您所能做的,最多只是建议。堆区主要分为两个部分:一块是 NEW Generation,另一块是Old Generation. 在NewGeneration中,有一个叫Eden的空间,主要是用来存放新生的对象,还有两个Survivor Spaces(from,to),它们的大小总是一样,它们用来存放每次垃圾回收后存活下来的对象。在OldGeneration中,主要存放应用程序中生命周期长的内存对象。在NewGeneration块中,垃圾回收一般用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个SurvivorSpace, 当Survivor Space空间满了后, 剩下的live对象就被直接拷贝到OldGeneration中去。因此,每次GC后,Eden内存块会被清空。在OldGeneration块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求. 垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收NEW中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。
  • PC寄存器  又叫程序计数器,每一个线程都有一个程序计数器,它在线程创建时创建,大小是一个字长,因此它可以保存一个本地指针。当Java虚拟机在执行一个方法时,程序计数器总是保存下一句将被执行的字节码的地址(直接地址或者相对地址)。
  • Java栈  每一个Java线程,都拥有一个单独的Java栈。它也是在线程创建时创建的,主要保存线程在运行过程中创建的基础类型的变量以及对象的引用。Java栈以帧为单位保存数据信息,虚拟机只对Java栈执行两种操作,即入栈和出栈。当调用一个Java方法时,虚拟机会从它的类型信息中查询出方法局部变量区和操作数区的大小,并以此为依据,分配栈帧内存,然后压入Java栈中。
附 虚拟机内存的申请过程:
  1. JVM 会试图为相关Java对象在Eden中初始化一块内存区域
  2. 当Eden空间足够时,内存申请结束。否则到下一步
  3. JVM 试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区
  4. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
  5. 当OLD区空间不够时,JVM 会在OLD区进行完全的垃圾收集(0级)
  6. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”

你可能感兴趣的:(java,jvm,虚拟机,存储,Class,generation)