一、JVM内存模型
1、程序计数器
记录正在执行的虚拟机字节码地址。
2、JAVA虚拟栈
JAVA方法执行时创建的栈帧,用于存储局部变量表、操作数栈、常量池引用等信息。可以用过-Xss来设置java虚拟栈内存大小,JDK1.4默认256k,JDK1.5以后默认1.5M。
java虚拟栈中可能会抛出以下异常:1、当线程栈请求的深度超过最大值,会抛出StackOverflowError异常。1、栈进行动态扩展时无法申请得到足够的内存,会抛出OutOfMemoryError。
3、本地方法栈
与java虚拟栈类似,只不过本地方法栈只为本地方法服务。
4、堆
对象都是在堆里分配内存。也是GC的主要区域。
堆可以分为:新生代、老年代
新生代:Eden + Survivor0+ Survivor1
大部分对象在Eden区中生成,当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。
老年代:在年轻代中经历了N(16)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
堆不需要连续的内存,并且可以动态增加,增加内存失败则会抛出OutOfMemoryError 异常。可以通过设置-Xms、-Xmx这两个虚拟机参数来指定程序的堆内存大小。
5、方法区
用于存放已经被加在的类信息、常量、静态变量,即编译器编译之后的代码数据。
方法区和堆一样,不需要连续的内存并且可以动态增加,动态扩展失败一样还是会抛出OutOfMemoryError 异常。
HotSpot虚拟机把方法区当成永久代来进行垃圾回收,但是很难确定永久代的大小,并且每次FullGC之后大小都会改变所以会经常抛出OutOfMemoryError 异常。因此为了更容易的管理方法区,从JDK1.8开始,移除永久代,并把方法区移动至元空间,它位于本地内存中而不是虚拟机内存中。
方法区是JVM的一个规范,永久代以及元空间都是其实现的一种方式,jdk1.8之后原来永久代的数据被分到了堆和元空间中。 元空间存储类的原信息,静态变量以及常量池存放在堆中。
6、直接内存
在 JDK 1.4 中新引入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在堆内存和堆外内存来回拷贝数据。