JAVA虚拟机内存
JAVA虚拟机内存,也叫JAVA内存,可以理解为Java虚拟机运行时数据区。
JVM内存结构
包括: 线程共享的方法区 和 堆, 以及每个线程私有的 JAVA栈,本地方法栈 和 PC计数器(程序计数器)。
JAVA堆
堆,是JAVA虚拟机中所管理的内存中最大的一块,此内存区域的唯一目的就是存放对象实例以及数组。
所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。
JAVA堆与垃圾回收的渊源
JAVA堆也是垃圾回收器管理的主要区域,因此也被称为:"GC堆"。
从内存回收的角度看,由于现在的收集器基本都采用分代收集算法,所以JAVA堆中还可以细分为:新生代和老生代。
再细致一点的划分如下:新生代又被进一步划分为Eden和 From Survivor区,最后From Survivor由FromSpace和
ToSpace组成。
- 新生代:新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例。
- 旧生代:用于存放新生代中经过多次垃圾回收仍然存活的对象。
JAVA虚拟机规范对JAVA堆的规定
JAVA堆可以处于物理上的不连续的内存空间中,只要逻辑上是连续的即可。在实现时,即可以实现成固定大小的,
也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx 和 -Xms 控制)。
关于OutOfMemoryError异常 :
如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
PS:OutOfMemoryError 有时简称为 OOM异常
JAVA栈(也叫做 虚拟机栈)
每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法
调用过程中的临时变量、参数和中间结果。
注意:JAVA栈是为JAVA方法服务的,本地方法栈是为Native方法服务的。
JAVA虚拟机规范中,对JAVA栈这个区域规定了两种异常状况:
- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError。
- 如果JAVA栈可以动态扩展,但是扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
与JAVA栈一样,本地方法栈区域也会抛出 StackOverflowError 和 OutOfMemoryError 异常。
PS:Native方法是指用其他语言写的方法,在JAVA中只能调用。
本地方法栈
用于支持native方法的执行,存储了每个native方法调用的状态。
方法区
方法区和JAVA堆一样,是各个线程共享的内存区域。
存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用持久代(PermanetGeneration)
来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。
JAVA虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与
JAVA堆区分开来。