从内存可分为:堆,虚拟机栈,程序计数器,本地方法栈,方法区五个部分
1)程序计数器
占用内存空间很小,属于线程私有,实现程序的分支,循环,跳转,线程恢复等基本功能,帮助多线程工作室,切换线程后,恢复到正确的执行位置。每个线程运行的时候都会有独立的计数器,是唯一一个没有OOM情况的区域
2)虚拟机栈
属于线程私有,生命周期和线程一致,存储的是一个个栈帧,每个栈帧对应的是一个被调用的方法。方法调用时,该方法所需内存空间在栈中进行分配,成为压栈,执行结束后,该方法所属的内存空间进行释放,成为弹栈(FIFO),
存储内容:局部变量,引用,操作数栈,动态链接,方法的出口
异常情况:StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。
OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。
3)本地方法栈
与虚拟房发展的作用和原理类似,区别是虚拟机栈是为虚拟机执行的java方法服务,本地房发展是为虚拟机使用的native方法服务
4)堆
属于线程共享的区域,在虚拟机创建时启动,FILO,唯一的目的是存放对象实例,几乎所有的对象实例都储存在其中
存储信息:对象实例和数组,执行时new创建的java对象,实例变量(是辣鸡回收机制的主要管理的区域)
JDK8以后:静态变量,常量池也并入堆中
异常情况:OOM 如果堆中没有内存完成实例分配,并且堆也无法再扩展时,抛出该异常。
5)方法区(1.8版本以前)
在jvm启动是被创建,存在于jvm中,物理内存空间跟堆区一样不是连续的,物理位置上是堆的一部分。属于线程共享区域,有一个非常重要的部分就是运行时常量池,这是每一个类或者接口的常量池运行时的表示形式,在类和接口被加载到jvm后,对应的运行时常量池就被创建出来。通过设置永久代初始分配空间,当jvm加载超过这个值,会报异常OOM
存储信息:类信息(名称,方法,字段等),静态变量,常量以及编译后的代码片段
永久代是jkd7以前,hotSpot虚拟机对方法区的一个落地实现
6)元空间(1.8版本以后)
跟方法区类似,但是是基于本地内存之中,元数据区大小可以使用参数-XX:MetaspaceSize和-XX:MaxMetaspaceSize指定
存储信息:类的元数据
也会发生OOM
版本 | 堆 | 方法区 | 元空间 |
---|---|---|---|
JDK7 | 堆内容 | 类的元数据,静态变量,常量池 | ----- |
JDK8 | 堆变量,静态变量,常量池 | ----- | 类的元数据 |
ps:我理解的是方法区与元空间本质一样,都是对永久代的实现方式,只是jdk7是在jvm中进行的一个实现,jdk8是基于本地内存中的一个实现
若存在什么偏差,欢迎斧正