共计 2484 个字符,预计需要花费 7 分钟才能阅读完成。
本文内容整顿自 博学谷狂野架构师
运行时数据区都蕴含什么
虚拟机的根底面试题
- 程序计数器
- Java 虚拟机栈
- 本地办法栈
- Java 堆
- 办法区
程序计数器
程序计数器是线程公有的,并且是 JVM 中惟一不会溢出的区域,用来保留线程切换时的执行行数
程序计数器(Program Counter Register)是一块较小的内存空间,能够看作是以后线程所执行字节码的行号指示器。分支、循环、跳转、异样解决、线程复原等根底性能都须要依赖这个计数器实现。
因为 Java 虚拟机的多线程是通过线程轮流切换并调配处理器执行工夫的形式实现的。为了线程切换后能复原到正确的执行地位,每条线程都须要一个独立的程序计数器,各线程之间的计数器互不影响,独立存储。
- 如果线程正在执行的是一个 Java 办法,计数器记录的是正在执行的虚拟机字节码指令的地址;
- 如果正在执行的是 Native 办法,这个计数器的值为空。
程序计数器是惟一一个没有规定任何 OutOfMemoryError 的区域
虚拟机栈
Java 虚拟机栈(Java Virtual Machine Stacks)是线程公有的,生命周期与线程雷同。
虚拟机栈形容的是 Java 办法执行的内存模型:每个办法被执行的时候都会创立一个栈帧(Stack Frame),存储
每一个办法被调用到执行实现的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
组成部分
- 局部变量表
- 操作数栈
- 动静链接
- 办法进口
异常情况
- StackOverflowError:线程申请的栈深度大于虚拟机所容许的深度
- OutOfMemoryError:虚拟机栈扩大到无奈申请足够的内存时
本地办法栈
本地办法栈(Native Method Stacks)为虚拟机应用到的 Native 办法服务
Java 堆
Java 堆(Java Heap)是 Java 虚拟机中内存最大的一块。Java 堆在虚拟机启动时创立,被所有线程共享。
作用:寄存对象实例。垃圾收集器次要治理的就是 Java 堆。Java 堆在物理上能够不间断,只有逻辑上间断即可。
蕴含元素
- 对象
- 数组
- 非动态变量
有什么异样
- java.lang.OutOfMemoryError: Java heap space:这种是 java 堆内存不够,一个起因是真不够,另一个起因是程序中有死循环
- java.lang.OutOfMemoryError: GC overhead limit exceeded:JDK6 新增谬误类型,当 GC 为开释很小空间占用大量工夫时抛出
办法区
办法区(Method Area)被所有线程共享,用于存储已被虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等数据。
和 Java 堆一样,不须要间断的内存,能够抉择固定的大小,更能够抉择不实现垃圾收集。
垃圾回收算法有哪些
罕用的垃圾回收算法有如下四种:标记 - 革除、复制、标记 - 整顿和分代收集。
标记 - 革除算法
从算法的名称上能够看出,这个算法分为两局部,标记和革除。首先标记出所有须要被回收的对象,而后在标记实现后对立回收掉所有被标记的对象。
这个算法简略,然而有两个毛病:
- 一是标记和革除的效率不是很高;
- 二是标记和革除后会产生很多的内存碎片,导致可用的内存空间不间断,当调配大对象的时候,没有足够的空间时不得不提前触发一次垃圾回收。
执行过程如下图
复制算法
为了解决效率问题,一种称为“复制”(Copying)的收集算法呈现了,他将可用内存按容量划分为大小相等的两块,每次只应用其中的一块。当这块的内存用完了,就将还存活这的对象复制到另外一块下面,而后再把已应用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存调配时也就不必思考内存碎片等简单状况,只有挪动堆顶指针,按程序分配内存即可,实现简略,运行高效。只是这种算法的代价是将内存放大为了原来的一半,未免太高了一点。
优缺点
- 长处:简略高效
- 毛病:代价是将内存放大为原来的一半,代价高
执行过程如下图
标记 - 整顿算法
复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更要害的是如果不想节约 50% 的空间就要应用额定的空间进行调配担保(Handle Promotion 当空间不够时,须要依赖其余内存),以应答被应用的内存中所有对象都 100% 存活的极其状况
对于“标记 - 整顿”算法,标记过程仍与“标记 - 革除”算法一样,然而后续步骤不是间接对可回收对象进行清理,而是让所有的存活对象都向一端挪动,而后间接清理掉端边界以外的内存,”标记 - 整顿“算法示意图如下:
标记 - 整顿算法解决了复制算法多复制效率低、空间利用率低的问题,同时也解决了内存碎片的问题。
分代收集算法
依据对象生存周期的不同将内存空间划分为不同的块,而后对不同的块应用不同的回收算法。个别把 Java 堆分为新生代和老年代,新生代中对象的存活周期短,只有大量存活的对象,所以能够应用复制算法,而老年代中对象存活工夫长,而且对象比拟多,所以能够采纳标记 - 革除和标记 - 整顿算法。
判断对象是否无效
援用计数算法
给对象增加一个援用计数器,每当一个中央援用它时,数据器加 1;当援用生效时,计数器减 1;计数器为 0 的即可被回收。
- 长处:实现简略,判断效率高
- 毛病:很难解决对象之间的互相循环援用(objA.instance = objB; objB.instance = objA)的问题,所以 java 语言并没有选用援用计数法治理内存
根搜索算法
Java 和 C# 都是应用根搜索算法来判断对象是否存活。通过一系列的名为“GC Root”的对象作为起始点,从这些节点开始向下搜寻,搜寻所有走过的门路称为援用链(Reference Chain), 当一个对象到 GC Root 没有任何援用链相连时(用图论来说就是 GC Root 到这个对象不可达时),证实该对象是能够被回收的。
在 Java 中这些对象能够成为 GC Root:
- 虚拟机栈(栈帧中的本地变量表)中的援用对象
- 办法区中的类动态属性援用的对象
- 办法区中的常量援用对象
- 本地办法栈中 JNI(即 Native 办法)的援用对象
本文由
传智教育博学谷狂野架构师
教研团队公布。如果本文对您有帮忙,欢送
关注
和点赞
;如果您有任何倡议也可留言评论
或私信
,您的反对是我保持创作的能源。转载请注明出处!