是什么?
将在一段时间不再使用,或在系统内部不再活跃的时候,则在系统中释放掉这部分的信息 。
运行时数据区
指令区:是线程独有的
虚拟机栈:也可以叫栈内存,是在线程创建的时候创建,也就说明了,一个线程是有一个独有的栈,虚拟机栈的生命周期是随着线程的结束而释放内存,对于栈而言不存在垃圾回收的问题,只要线程结束,那么生命周期和线程是一致的,是栈会存储基本类型变量、实例方法、引用类型变量,都是在栈内存中分配,就是线程执行独有的方法的时候,会将方法区的对应的对象,类信息copy需要的部分信息到栈内存中,执行每一个方法的时候可以理解为是一个栈帧,具体看个人怎么去理解JVM栈内存,栈是遵循一个LIFO的一个原则,而栈一般是由三个部分组成,局部变量表,栈数据区,操作数栈 。
局部变量表:存储报错的行数和方法使用到的局部变量等
操作数栈:保存计算过程中的结果,且作为计算过程中的变量临时存储空间 。
栈数据区:除了局部变量和操作数栈,栈还需要一些数据来支持常量池的解析,这里的栈数据区就是保存常量池的指针、方法返回地址等,另外发送异常和处理异常代码等,所以栈数据区还有一个异常处理表 。
栈执行过程:当一个线程在执行某个方法的时候,就是在栈内运行的,而栈是遵循LIFO的原则,那么就可以解释当A方法调用B方法的时候,只有B方法执行完了,那么A方法才会继续向下执行,那么在调用的时候是先调用A方法,那么A方法是先进栈,而B是后进栈的,B方法执行完了,弹出栈,继续A方法,A方法执行完了,那么则出栈 。
文章插图
文章插图
?
本地方法栈:用于本地方法调用,允许java调用本地方法,具体可以看本地接口上述,本地接口如同一个大的存储每一个对象,而本地方法栈就是存储这个对象要执行的方法信息 。
程序计数器/PC寄存器:指向方法区中的方法字节码(用于存储指向下一条指令的地址,也就是要指向的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,如果执行的方法是本地方法,寄存器值为undefined,如果不是那么寄存器会存放当前环境指针、程序计数器、操作栈指针、计算的变量指针等信息 。
数据区:是所有线程共享的
方法区:保存类的元结构信息、运行时常量池、静态变量、常量、字节码、在类/实例/接口初始化用到的特殊方法等,方法区是可以调节大小的,且方法区是可以会进行垃圾回收的,所以可以理解方法区是一块逻辑区域 。
堆:存储Java对象和数组等,但这个对象在堆中的首地址会在栈存储,堆内存的大小是可以调节的 。
堆可以说是Java一块比较特殊的区域,因所有的Java对象实例都存储在这个地方,那么Java实例多了,则需要回收,那么也不可能每一次使用完这个实例之后就把这个实例在内存马上销毁,如果过多几秒时候又使用到了呢?
所以针对这种情况,Java堆的设计就有点特殊了 。
堆 = 新生代 + 老年代 + 永久代(特殊)
新生代 = Eden + sv0+ sv1
新生代:主要存储一个新的对象,通过不同的垃圾回收策略进行计算什么时候进入老年代,什么时候进行回收,具体看垃圾回收机制 。
TLAB(Thread-local allocation buffer)区:是一个线程独有的区域,
是为了加速内存分配而存在的,也就是线程独享的缓冲区,避免多线程问题,没有锁的问题,也就没有了锁对资源的开销,提高对象分配使用,但这个区域是只存储小对象的,无法进入TLAB区的对象会直接进入堆,而TLAB区对对象是否进入的条件是按照对象的大小是否小于整个空间的64/1,这是一个默认的比例值,这个比例值是可以调整的 。
老年代:存储在新生代达到一定阈值(默认15),则进入老年代 。
永久代:这是一个非常特殊的区域,这个是属于Hotspot这个虚拟机比较独有的,不同的虚拟机实现不一样,但如J9、JRockit是没有永久代的概念,永久代只是一个概念上的意义,永久代也会发生垃圾回收,但条件比较苛刻,稍后会在JDK6、7、8的区别中讲到,而永久代在JDK8时就给移除了,改为元空间 。
推荐阅读
- javascript中的事件
- 哇塞!GitHub 上这些 Java repo 太强了吧,看完都变大佬
- 一名高级的Javaer,应该了解的 MYSQL 高级知识点
- 我也没想到,Java开发 API接口可以不用写 Controller了
- Java中的封装、继承和多态,你真的都懂了吗
- 什么是 Java 的无服务器化?
- Javascript实现两变量值的互换
- java按顺序执行线程
- linux系统上查看载体为实体机还是虚拟机
- 线程安全问题无大小:Java中的线程安全之操作共享数据分类