-
运行时数据区域
要理解虚拟机内存溢出需要先了解java内存区域即:运行时数据区域,运行时数据区域主要分为:
- 堆
- 方法区
- 虚拟机栈
- 本地方法栈
- 程序计数器
1.1 程序计数器
程序计数器是记录当前线程的执行到第几行即行号指示器(线程私有),字节码解释器通过计数器获取下一条该执行的命令行。例如cpu执行多线程的代码时,因为系统采取的时间片轮转法,线程可能不会一次执行完,程序计数器会记录相对应的线程执行到第几行,当其再获得cpu时则会从该行继续执行。
1.2**java虚拟机栈**
java虚拟机栈是线程私有的,生命周期与线程相同。虚拟机用于描述Java方法执行的内存模型,每个方法执行时多会同时创建一个栈帧用于存储局部变量表、 操作栈、动态链接、方法出口等信息,
其中变量表存放了编译期可知的八大基本类型数据或者对象的引用。
每一个方法被调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。
对于该区域虚拟机规定两个异常状况:1、如果线程请求的栈深度大于虚拟机允许的深度,抛出*Error异常;2、虚拟机扩展是无法申请到足够的内存是会抛出OutOfMemoryError
1.3 本地方法栈
本地方法栈和虚拟机栈的作用是十分相似的,不同的是本地方栈是为虚拟机要用的Native方法服务,
简单来说一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern “C”告知C++编译器去调用一个C的函数,与虚拟机栈一样本地方法栈也会抛出*Error异常与OutOfMemoryError异常。
1.4 java堆
java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,唯一的作用是存放对象实例绝大数对象实例都在这里分配内存,new一个对象时会形成一块逻辑上联系的空间存储该对象所有实例数据值的结构化内存,相当于调用构造方法进行实例初始化,然后返回一个引用(主流:句柄、直接指针)通过这个引用去调用对象实例,当堆没有内存完成实例分配,并无法再扩展则抛出OutOfMemoryError异常
1.5**方法区**
方法区是被所有线程共享的内存区域,它主要尺寸已经被虚拟机加载的类信息、常量、静态变量、及时编译后的代码等数据例如(对象类型、父类、实现的接口、方法的地址信息),同时方法区主要是运行时常量池;运行时常量池存储生成的各种字面量和符号引用(常见的是字符串,所以利用比较多是String类的,intern()),无法再扩展则抛出OutOfMemoryError异常
*直接内存 并不是虚拟机运行时数据区的一部分,主要NIO(New Input/Output)它可以使用Native函数库直接分配堆外内存,通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作