二 JVM
1、内存结构
程序计数器 : 程序计数器是一块较小的内存空间(线程私有),它可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个程序计数器的值来选取吓一跳执行的字节码指令,分支、循环、跳转,异常都要依赖这个计数器,所以程序计数器是线程私有的
java虚拟机栈 :描述的是Java方法执行的内存模型,和线程的生命周期一样(线程私有)。每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、出口信息、动态链接等。这块区域会出现两种异常StackOverflowError和OOM
本地方法栈 :为虚拟机使用到的Native方法服务和虚拟机栈类似(线程私有)
Java堆:是Java虚拟机所管理的最大一块内存(线程共享),此内存最大的目的就是存放对象实例,几乎所有的对象都在这里分配内存。
方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据(线程共享)
运行时常量:方法区的一部分,类信息中除了有类的字段、方法、接口等描述信息外还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用
直接内存: (也就是堆外内存) 内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。使用未公开的Unsafe和NIO包下ByteBuffer来创建堆外内存。
2、垃圾回收器
判断对象可否回收的方法是:可达性分析算法,从GcRoot对象从上往下搜索,搜索的过的路径叫引用链,当一个对象没有饮用链的时候就是垃圾对象了
可以作为GcRoot的对象可以是:
a、虚拟机栈(栈帧中的局部变量表)中引用的局部变量表
b、方法区中的静态引用对象
c、方法区中的常量引用对象
d、本地方法栈中引用的对象
引用方式
a、强引用 永远不会回收
b、弱引用 每次都回收,只能生存到下次垃圾回收发生之前
c、软引用 先回收,不够再回收
d、虚引用 无法通过虚引用获取对象实例,唯一目的就是回收时只会收到一个回收的通知
回收条件
a、如果对象进行可行性分析后发现没有与GcRoot相连的引用链,则该对象被第一次标记并进行筛选,筛选条件为是否有必要执行该对象的finalize方法,如果对象没有覆盖finalize方法或者finalize方法已被虚拟机执行过了(finalize只会执行一次),则不会不必要执行finalize方法,对象就会被回收,反之如果对象覆盖了finalize或者没有被执行过,那么对象会被放进F-Queue的队列中,之后由虚拟机建立的低优先级的finalizer线程去执行,而虚拟机不必等待线程执行结束,虚拟机只负责建立线程,其他交由线程去做
b、F-Queue的对象进行二次标记,如果对象在finalize方法中拯救了自己,机关联上了GcRoot的引用链,如把this关键字赋值给其他变量,那么在第二次标记的时候该对象从即将回收的集合中移除,如果对象还没有拯救自己,那么就会被回收
方法区回收