一直想要写一些博客,但是觉得个人能力不够,也就没有祸害别人。今天周志明书籍《深入理解java虚拟机》中得到一些启发所以来写一下关于java内存分配问题!
1. java内存分布区域大概分为以下几个部分
(1) 程序计数器
程序计数器(Program Counter Register)是一块内存较小的内存空间,他可以看作当前线程所执行的字节码的行号指示器。如果当前线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是Native方法,这个计数器则为Undefined。
(2)java虚拟机栈
Java虚拟机栈(java Virtual Matchine Statcks)也是线程私有的,它的生命周期和线程周期相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时都会创建一个栈帧(Stack Frame)用用于存储局部变量、栈操作数、动态链表、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应这一个栈帧在虚拟机栈中入栈到出栈的过程。
(3)本地方法栈
本地方法栈(Native Method Stack)和虚拟机栈发挥的作用非常相似,它们之间的区别不是虚拟机为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native 方法服务。
(4)java堆
Java堆(java heap)是java虚拟机所管理的内存中最大的的一块。java堆是被所有线程共享的一块内存区域,在虚拟机创建的时候。此区域的唯一目的就是存放对象实例,几乎所有的对象都在这里分配内存。
(5)方法区 Method Area
方法区(Method Area) 和java堆内存一样,,是各个线程共享的区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
虽然java 虚拟机规范把方法区描述为一个逻辑部分,别名是Non-Heap(用于区别)java堆!
2. OutOfMemoryError异常
(1)java 堆内存溢出
java.lang.OutOfMemoryError: Java heap space
常见会出席抛出这些异常的情况有以下几种情况:
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用的第三方软件中的BUG;
- 启动参数内存值设定的过小;
(2)虚拟机栈和本地方法栈
java.lang.StackOverflowError :
如果线程请求的栈深度大于虚拟机所允许的最大深度就会抛出 java.lang.StackOverflowError。
如果虚拟机在扩展时无法申请到足够的内存空间,则会抛出OutOfMemoryError。
(3)方法区和运行时常量池溢出
java.lang.OutOfMemoryError: PermGen space PermGen space
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域, 这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中, 它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对 PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen space错误, 这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。