Java虚拟机的内存分配

首先看看Java虚拟机运行时内存主要的分块:


1.程序计数器

一块较小的内存,它的作用可以看作是当前线程锁执行的字节码的行号指示器。任一时刻一个处理器只会执行一条线程中的指令,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器。

2.Java虚拟机栈

与程序计数器一样,也是线程私有的,负责几乎局部变量表、操作栈、动态链接、方法出口等信息,每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈和出栈的过程(也称之为线程栈,线程栈分配的大小可以在jvm启动参数的-Xss中配置,当使用虚拟机默认参数时,栈深度在大多数情况下达到1000-2000完全没有问题,线程栈的大小开大了,系统可生成的线程数就会相应减少),当线程请求的栈深入超过虚拟机所允许的深度,将抛出StackOverFlowError异常,若虚拟机动态扩展后仍无法请求到足够的内存,则抛出OutOfMemoryError异常。

3.本地方法栈

与虚拟机栈的作用是类似的,一个是为虚拟机执行Java方法服务,一个是为虚拟机执行Native方法服务,有的虚拟机直接把将这两种栈合二为一。

4.Java堆

专门存放Java对象的内存,是垃圾收集器管理的主要区域,也称为GC堆,其中又分为新生代和老年代,其大小由jvm启动参数来决定,如–Xms 128m –Xmx 512m表示初始大小为128m,内存不足时可动态扩展,最多扩展到512m。

5.方法区

存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据,又叫Non-Heap(非堆),也有人称之为“永久代”(并不一定是“永久”存在的,它也可能被垃圾收集器回收),可通过虚拟机的-XX:PermSize和-XX:MaxPermSize来限制大小。

6.运行时常量池

属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用,如一些在运行时才生成的常量。

7.直接内存

不属于Java虚拟机管理的内存,一般是在使用NIO的时候分配的内存空间,可通过-XX:MaxDirectMemorySize指定,若不指定则默认使用-Xmx的大小。若虚拟机的内存开辟过大,会导致直接内存的不足,而导致OutOfMemoryError的错误,这时候需要把Java虚拟机的内存占用调低