概述
Java虚拟机具有自动管理JVM内存的机制,无需为new的对象写free和delete代码,控制内存的权利在Java虚拟机手中,不易出现内存泄露和内存溢出的情况
内存泄漏
是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
内存溢出
内存溢出(Out Of Memory,简称OOM)是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存
运行时数据区
什么叫运行时数据区
Java虚拟机(JVM)将它所管理的内存划分为几个分工不同的数据区域,这些数据区域作用、创建和销毁时机各不相同,有的区域随着虚拟机进程的启动而一直存在(堆+方法区),有些区域依赖用户线程的启动而产生,结束而销毁(程序计数器+虚拟机栈+本地方法栈)
程序计数器
程序计数器相对来讲是比较小的一块内存区域。可以看做是当前线程当中所执行的字节码命令的行号指示器,存储的是下一个字节码指令的地址。控制着程序的流转
虚拟机中的多个线程争抢CPU计算资源,不断的发生着上下文切换,切换后 程序依旧可以通过计数器回到正确的执行指令的位置,每个线程都会有一个单独的程序计数器,此为线程私有。
线程如果执行的是Java方法,程序计数器记录的是正在执行的虚拟机字节码 指令的地址。如果是native方法,计数器值为空
程序计数器当中不会发生OutOfMemoryError不会发生内存溢出。
虚拟机栈
线程私有。生命周期与线程相同,虚拟机描述的是Java方法执行的线程内存模型,每个方法被执行的时候,Java虚拟机都会同时创建一个栈帧(栈帧是方法运行期间的一种重要的基础数据结构)用于存储局部变量表、操作数栈、动态链接、方法出口等信息每一个方法从被调用到执行完毕的过程就对应这一个栈帧在虚拟机栈中从入栈到出栈
局部变量表
局部变量表存放内容
1、编译期间已确定的8种基本数据类型
2、对象引用(句柄、对象起始地址引用指针)
3、returnAdress类型(一条字节码指令的地址)
局部变量表特点
这些数据类型在局部变量表当中使用变量槽为单位进行存储,64位长度的long和double类型占用两个变量槽,其他数据类型都是一个,一个方法的局部变量表编译时期大小已定,当一个方法入栈时,局部变量表在栈帧中分配多大的空间是完全确定的,且方法运行期间不变。
不同虚拟机一个对于变量槽实现方式不同,变量槽在不同的虚拟机下的占用大小(32bit还是64bit)是具体虚拟机决定的。
两种异常
StackOverFlowError
栈溢出:在虚拟机状态不允许动态拓展情况下,线程请求的栈深度大于虚拟机所允许的深度。
OutOfMemoryError
内存溢出:在虚拟机状态允许动态拓展情况下,如果拓展是还是申请到足够的内存。
本地方法栈
本地方法栈与虚拟机栈发挥的作用非常相似,虚拟机栈运行Java方法,本地方法栈运行native方法,在Hot-Spot虚拟机两者是合二为一的,本地方法栈也是在栈深度溢出或者栈拓展失败的时候分别抛出StachOverFlowError和OutOfMemoryError异常。