1.程序计数器
是一块很小的内存空间,用来记录每一个线程运行的指令位置;是线程私有的;每一个线程都拥有一个程序计数器;记录这个线程运行到哪一行,生命周期与线程生命周期保持一致;是运行时数据区中唯一一个不会出现内存溢出的空间;运行速度最快。
2.本地方法栈
用来运行本地方法的区域;
是线程私有的;
空间大小可以调整;
可能会出现栈溢出;
3.java 虚拟机栈
每个线程在创建时都会创建一个虚拟机栈,是线程私有的; 栈是运行时的单位,来管理方法的调用运行,运行完出栈即可;
是用来运行java方法的区域
可能会出现栈溢出(内存溢出)
栈不会出现垃圾回收的方式
运行原理:
先进后出的结构
最顶部的称为当前栈帧
栈帧结构:
一个栈帧包含:
局部变量表(存储在方法中声明的变量)
操作数栈(实际计算运行)
动态链接
void A(){
B();//B方法的地址
}
方法返回地址
4.堆
基本作用特征
是存储空间,用来存储对象(所有对象实例在产生时都应该分配在堆上)
是内存空间最大的一块儿区域
在jvm启动时就被创建,大小可以调整(jvm调优)
存在垃圾回收,并且是垃圾回收的重点区域
所有的线程共享java堆
堆内存区域划分
新生区(年轻代/新生代)
Eden(伊甸园区)对象刚刚创建存储在此区域
Survivor幸存者0区,幸存者1区
老年区
![](https://img-blog.csdnimg.cn/img_convert/bf82c7fa775d075480748695eee75442.png)
创建对象时,对象在堆内存中如何分布?
每次新创建的对象都会放在伊甸园区,当垃圾回收时,先回收掉伊甸园区中的废弃对象,然后剩余的转入此时空的幸存者区域如幸存者1区,当再次进行垃圾回收时,伊甸园中存活的对象以及幸存者1区的存活对象都转入幸存者2区,此时幸存者1区为空,我们每次都维持一个幸存者区域为空。当我们每次进行垃圾回收时,还会对每个对象标注回收次数,当回收次数到达15次(最大15,可以进行调整)还未被回收时,就将其转入老年区。老年区中的对象基本上不会再被回收,只有老年区内存不足时,才会对其进行回收
为什么要分区?
可以根据对象的存活的时间放在不同的区域,垃圾回收时可以区别对待;频繁回收年轻代,较少回收老年代。
将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及GC概率,针对分类进行不同的垃圾回收算法,对算法扬长避短
创建对象,在堆内存中分布?
1.新创建的对象,都存储在伊甸园区
2.当垃圾回收时,将伊甸园区中的垃圾对象直接销毁,将存活的对象移动到幸存者1区
3.之后创建的新对象还是存储在伊甸园区,再次垃圾回收到来时,将伊甸园中的存活对象移动到幸存者2区,同样将幸存者1区的存活对象移动到幸存者2区,每次保证一个幸存者区为空的,相互转换
4.每次垃圾回收时,都会记录此对象经历的垃圾回收次数,当一个对象经历过15次回收,仍然存活,就会被移动到老年代,垃圾回收次数,在对象头中有一个4bit的空间记录,最大值只能是15.
5.老年区回收次数较少,当内存空间不够用时,才会回收老年代的对象,如果还不够,则栈溢出。
5.方法区
类加载器加载出的类信息存放于方法区
作用:主要用来存储加载的类信息,以及即时编译期编译后的信息,以及运行时常量池
特点:在jvm启动时创建,大小也是可以调整,是线程共享的,也会出现内存溢出。
方法区、堆、栈的交互关系
![](https://img-blog.csdnimg.cn/img_convert/b59b62d73c2361a287fe3b529f10b497.png)
方法区存储类信息(元信息)
堆中存储创建的对象
栈中存储对象引用
方法区大小设置
-XX:MetaspaceSize 设置方法区的大小
windows jdk默认的大小是21MB
也可以设置为-XX:MaxMetaspaceSize 的值是-1,级没有限制. 没有限制 就可以使用计算机内存
可以将初始值设置较大一点,减少了FULL GC发生
方法区内部结构
类信息
以及即时编译器编译后的信息,
以及运行时常量池(指的就是类中各类)
方法区的垃圾回收
在Full GC 时,才会发生方法区的垃圾回收。
主要是回收类信息,类信息的回收条件是比较苛刻的,满足一下三点:
1.在堆中,该类及其子类的对象都不存在了
2.该类的类加载器不存在了
3.该类的Class对象不存在
也可以认为,一个类一旦被加载,这个类信息就不会被卸载回收;
总结:
程序计数器,java栈,本地方法栈是线程私有的
程序计数器不会出现内存溢出
java栈,本地栈,堆,方法区可能会出现内存溢出
java栈,本地栈,堆,方法区大小是可以调整的
堆,方法区是线程共享的,是会出现垃圾回收的
![](https://img-blog.csdnimg.cn/img_convert/58f4616758c4b7b360526249ecae997e.png)
jvm运行时数据区,分为程序计数器(是线程私有的,记录每个线程运行到哪一行),本地方法栈(运行本地方法),java虚拟机栈(管理方法的调用和运行,每个线程都拥有一个虚拟机栈),堆(用来存储实例对象,是线程共享的),方法区(用来存储类的信息,是线程共享的)。