概述
上一篇
安卓面试总结(4)——Java 多线程II
上一篇写了多线程、锁机制的内容,写的不是很详细,需要配合一些知识来回顾,但是看完后应该会有一个大概了吧。接下来的 JVM 有点复杂,可能安卓也用不到,但是能够说清楚的话,面试还是有一定优势吧,至少肚子里有东西,不会慌,有利于提高信心。
一、运行时数据区域
又是别人的图啊,这个很简洁明了。
-
程序计算器
- 记录正在执行的虚拟机字节码指令的地址(执行本地方法时为空)
-
Java 虚拟机栈
- 储存局部变量表、操作数栈、常量池引用等信息
- 从方法调用直至完成,对应一个栈帧在 JVM 栈中入栈过程(方法 -> 栈帧 -> 调用)
- 异常:
- StackOverflowError:线程请求深度操作最大值(16?)
- OutOfMemaryError:栈动态扩展时无法满足足够内存
-
本地方法栈:为本地方法服务
-
堆:
-
所有对象都在这里分配内存,是垃圾收集的主要区域
-
堆不需要连续内存,并且可以动态增加其内存,失败时会 OutOfMemaryError
-
-
方法区:
- 用于存放已被加载的类信息、常量、静态变量、即时编译的代码等数据(4个)
- 不需要连续内存,可动态扩展,失败会异常
- 垃圾回收主要为常量池和类的卸载(比较难实现)
-
运行时常量池:也是方法区的一部分
- Class 文件中的常量池(编译器生成的字面量和符号引用)会在类加载后被放入这个区域
- 除了在编译期生成的常量,还允许动态生出,如 String 类的 intern 函数
-
直接内存
- JDK1.4 中引入 NIO 类,可以使用 Native 函数库直接分配堆外内存
二、垃圾收集
- 针对目标:堆和方法区,线程部分会随线程结束而消失(面试被问了,居然没记住)
- 判断一个对象是否可被回收
- 引用计数法:
- 为对象添加一个引用技术区,增加引用加一,引用失效减一,0 的时候可被回收
- 两个对象循环引用时(互相持有),计数永远不为 0,无法被回收
- 可达性分析算法(JVM使用):
- 以 GC ROOTS 为起点进行搜索,可达的对象是存活的,不可达则可回收
- GC ROOTS 包含:
- 虚拟机栈中局部变量表中引用的对象
- 本地方法栈中 JVM 中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
- 引用计数法:
三、方法区的回收
- 方法区主要存放永久代对象(JDK1.8 后移到堆、内存),回收率低
- 主要是对常量池的回收和卸载(为避免内存溢出,大量使用反射和动态代理 JVM 需要类卸载)
- 类卸载条件(不一定卸载)
- 该类所有对象实例已被回收,堆中怒不存在该类任何实例
- 加载该类的 classloader 已被回收
- 该类对应 class 对象在任何地方未被引用,也就无法在任何地方通过反射访问该类
- 类卸载条件(不一定卸载)
四、finalize()
当一个对象可被回收时,finalize() 会被执行,但有且只有一次(可以使用引用自救一次)
五、引用类型
- 强引用:使用 new 创建新强引用
- 软引用:SoftReference<T>,只有在内存不足时才会被回收
- 弱引用:WeakReference<T>,如果一个对象所有引用都是弱引用,那么将被回收
- 虚引用:PhamtomReference<T>,虚引用持有对象会在任何时候被回收(无法获取实例,仅仅在回收时得到通知)
六、垃圾收集算法
- 标记 - 清除
- 标记阶段:检查是否为活对象,打上标记
- 清除阶段:进行对象回收,取消标志位,还会合并相邻分块
- 在分配时:搜索空闲链表中空间大于新对象 size 的 block 块,大于还会返回空闲块
- 不足:
- 标记和清除效率都不高
- 会产生大量不连续内存碎片
- 标记 - 整理
- 让所有存活的对象都向另一端移动,然后清除掉端边界以为的内存
- 优点:不会产生内存碎片
- 不足:需要移动大量对象,处理效率比较低
- 复制
- 将内存划分为大小相等的两块,每次只使用其中一块,这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
- 分代收集
- 根据对象存活周期将内存划分为几块,不同块采用适当的收集算法
- 新生代:复制,老年代:标记清除or标记整理
七、垃圾收集器
-
概述
-
主要记住 CMS 和 G1 就够了吧。
-
新生代:G1、Serial(串行)、ParNew(并行)、Paraller Scavenge(可控吞吐量,优先吞吐量)
-
老年代:G1、CMS、Serial old(串行)、Parallel old(并行)
-
-
CMS 收集器:以获得最短回收时间为目标的收集器
- 初始标记:stop world,速度很快,GC Roots直接关联
- 并发标记:GC Roots Tracing,所有存活对象
- 重新标记:stop world,修正并发期间变动(时间久),耗时比初始长,比并发短
- 并发清除
-
G1 收集器
- 空间整合,采用标记整理算法(复制?),不会产生内存空间碎片
- 可预测停顿(处理的是 region)
- 内存布局改变,将整个 Java 堆划分为大小相等的独立区域 Region
- 还有新生代、老年代概念,但不是物理隔离了,收拾 Region 的集合
- 和 ParNew 类似,当新生代达到一定比例时收集,和 CMS 一样收集老年代有短暂停顿
-
Serial 收集器:单线程收集器,效率高
-
ParNew 收集器:Serial 的多线程版(新生代默认)
-
Parlllel Scavenge:多线程收集器,可控制吞吐量 <-> 停顿时间
下一篇
安卓面试总结(6)——Java 虚拟机 II
最后
以上就是背后大地为你收集整理的安卓面试总结(5)——Java 虚拟机 I的全部内容,希望文章能够帮你解决安卓面试总结(5)——Java 虚拟机 I所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复