java虚拟机在执行java程序的时候,会将管理的内存区域划分成若干个不同的数据区域
- 程序计数器
可以看成是当前线程执行字节码指令的行号指示器,字节码解释器工作时,是通过改变这个指示器的值来选取下一条执行的字节码命令,分支,循环,跳转,异常处理以及线程恢复都是需要这个计数器来完成。
程序计数器是线程私有,因为java的多线程本质上是在同一时刻是由一个处理器(内核)来进行时间片的轮转来实现的,那么,当一个线程执行完之后,切换到另外一个线程,为了防止各个线程之间相互干扰,那么每个线程内部都会有一个程序计数器。
如果线程执行的是java方法,那么这个程序计数器指向的是正在执行的虚拟机字节码的指令地址,如果是Native方法,那么值为undefined ,这个区域是唯一一个没有定义out of memory的区域。
- 栈
1.java 虚拟机栈 虚拟机为java方法服务
java虚拟机栈是线程私有的,生命周期和线程相同。
java虚拟机栈描述的是Java方法执行时的内存模型:每个方法在执行时都会创建一个帧栈(Stack Frame),用于局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法的调用直至执行完成的过程,都对应着,一个帧栈在虚拟机中从入栈到出栈的过程。
局部变量表存放:基本数据类型,对象引用,以及returnAddress的地址(指向了一条指令字节码的地址),由于这些都是固定的,所以局部变量表在编译期间内完成内存的分配,在方法执行期间保持不变。
两种异常:StackOverflowError和OutOfMemoryError
如果线程请求的栈深度大于虚拟机的栈深度,那么就会StackOverflowError
如果虚拟机的栈是可以动态扩展的,那么,当申请的满足不了要求的时候,就会出现OutOfMemoryError
思考:1.方法执行时,具体的过程,以及内存的分配? 2.为什么是stack frame,怎么理解?
链接
2.本地方法栈 虚拟机为本地Native服务
同样也会出现StackOverflowError和OutOfMemoryError
- 堆
java堆是线程共有的,几乎所有的对象实例和数组都在堆上进行分配,是GC的主要区域。
由于GC很多采用的是分代回收的算法,所以java堆可以细分为:Eden,From Surivivor,To Surivivor
可能出现 OutOfMemoryError
- 方法区(Method Area)
和java堆一样,是线程共享区域。
用于存储,已经被虚拟机加载的类信息,常量,静态变量和即时编译后的代码等数据。
方法区的内存回收主要是针对常量池的回收以及类型的卸载,一般这个区域内存的回收效果常常不是那么 满意,尤其是类型卸载的时候,条件非常的严格。但是对这个区域的回收也是必要的,否则会出现内存泄漏的bug。
可能出现OutOfMemoryError
- 常量池(Constant Pool Table)
方法区的一个部分,用于存放编译期生成的各种字面常量和符号引用,这部分内容将在类加载后进入运行时的常量池中存放。
可能出现OutOfMemoryError。
- 直接内存(Direct Memory)
直接内存并不是虚拟机运行时数据区的一个部分,也不是java虚拟机规范中的定义的内存区域。但是这部分的内存也被频繁的调用,因此,也可能导致OutOfMemoryError。
在JDK1.4后,新加入了NIO(New Input/Output)类,是一种基于channel与缓冲区的IO方式,它可以使用Native库直接分配堆外内存,然后通过一个存储在堆中的DirectByteBuffer对象来作为这块内存的引用进行操作,加快了速度,但是也会出现OutOfMemoryError.