深入理解JVM

JAVA内存模型

运行时数据区域,JVM在执行JAVA程序是将其所管理的内存划分为不同的数据区域

程序计数器,线程私有

记录当前线程执行字节码的行号,多线程切换后能够正确的恢复到程序执行的位置

虚拟机栈 ,线程私有,生命周期与线程相同

虚拟机栈描述的是JAVA方法执行的内存模型

方法执行时会创建一个栈帧的数据结构,栈帧存储了局部变量表(方法的参数,方法中的局部变量),操作栈,动态链接,方法出口等信息

方法的执行过程就是栈帧进栈和出栈的过程

本地方法栈,与虚拟机栈功能类似,为本地方法服务

Java堆区(Heap)  线程共享的

虚拟机管理的最大一块区域 

用来存放对象实例

也是垃圾收集器主要工作的区域   按照内存回收的角度又分为

                        新生代(Eden ,survivor) 经验性 死亡率高达97%需老年代提供担保  用少量存活对象的复制代价完成清理

                        老年代   存活率高 用  标记-清除   或   标记-整理算法  为新生代提供担保空间,一旦存活对象survivor无法容纳直接进入老年代 

方法区 线程共有的

主要用来存放类信息 ,静态变量 ,常量

内存回收目标有两个;类型的卸载   常量池的回收

    运行时常量池 :用来存放 字面量 ,符号引用 。

对象是否存活?

引用计数法:为对象添加一个计数器,对象每被引用一次计数器加一,当一个引用失效计数器减一,当计数器为0时说明对象不可用

缺点:无法解决循环引用的问题 A.S=B ,B.S=A  python用次算法

可达性分析算法(跟搜索算法)

通过一系列的‘’GC Roots‘’ 的对象向下搜索 搜索走过的路径称为引用链 若对象到GC Roots没有任何引用链时 对象就是不可用的

可作为GC Roots 的对象

                           方法区的静态变量,常量 引用的对象

                           虚拟机栈 局部变量表中引用的对象

                           本地方法栈 中本地方法引用的对象


标记-清除算法

首先标记出所有要回收的对象,标记完成后统一清理所用被标记的对象

缺点:产生大量的空间碎片,分配大对象是无法找到足够的连续内存

标记-整理算法

让所有存活的对象移动到内存的一端,清理掉边界外的内存。

复制算法 

将新生代分为一块Eden区 和两块Survivor区域(8:1:1),每次使用Eden区和一块Survivor区,回收时将存活的对象复制到另一块Survivor区

最后清理掉Eden区,和Survivor区。

利用了新生代的朝生夕死的特性,付出少量的存活对象的复制代价完成清理 ,需要老年代担保

分代收集算法:根据对象存活周期不同分为 新生代,老年代

垃圾收集器

serial收集器

单线程收集垃圾,用户线程 STOP THE WORD

优点:无线程交互的开销 ,专心做垃圾收集工作

ParNew收集器 多线程版serial   

Parallel Scavenge收集器(吞吐量)

吞吐量=用户线程时间 / CPU总消耗时间  适合后台运算不需要太多交互的任务

CMS 垃圾收集器(Concurrent Mask Sweep)最短停顿时间 重视服务的响应速度

1 初始标记  快速扫描GC Roots直接引用的对象  需要STOP THE WORD

2 并发标记  与用户线程并行 

3 重新标记  STOP THE WORD 标记那些并发标记因用户线程改变的对象引用

4 并发清理  

缺点:标记-清除算法 产生空间碎片   

            并发清理时产生的垃圾无法进行收集,产生浮动垃圾

             并发标记与用户线程并行效率不高

G1 垃圾收集器(Garbage first)

致力于非常精确的控制停顿

G1将堆内存划分为多个大小固定的独立区域(Region),并跟踪每块区域的垃圾堆积程度,计算垃圾回收价值(回收需要的时间,回收获得的空间)在后台维护一个优先表,根据每次允许的收集时间来优先回收价值最大的区域。


对象优先分配在Eden区 

大对象直接进入老年代,避免在Eden区和Srvivor区发生大量内存拷贝

长期存活的对象进入老年代,对象每熬过一次minor GC年龄+1 增加到15晋升老年代

动态年龄划分:在Survivor空间中所有相同年龄的所有对象大小大于Survivor的一半,大于等于与该年龄的对象进入老年代


类加载机制

加载  

通过类的权限名获取次类的二进制字节流,将字节流代表的静态储存结构转换为方法区的运行时数据结构

在java堆生成java.lang.Class对象作为方法区这些数据的访问入口

 连接   分为三个阶段(验证,准备,解析)

验证是连接的第一个阶段

1文件格式验证 字节流是否满足Class文件要求 ,

2元数据验证(父类是否继承final修饰的类,不是抽象类是否实现了父类或接口的全部方法)

3字节码验证

4符号引用验证

准备

准备阶段是正式为类变量分配内存(方法区)并设置初始值(零值)的阶段,

解析

符号引用(用符号描述所引用的目标)变成直接引用(直接指向对象的指针或句柄)

 初始化

执行java代码


双亲委派模型

两个类是否相等,不仅要求是同一个Class文件还必须是一个类加载器加载的

如果一个类加载器收到了类加载的请求,它首先不会尝试自己去加载这个类,而是把这个请求委托给父类去完成,因此所有类加载的请求都应该传送到顶层的启动类加载器,只有当父类反馈自己无法完成这个加载请求(他的搜索范围没有找到这个类)时子类加载器才会自己去尝试加载这个类。
















你可能感兴趣的:(深入理解JVM)