1、jvm内存区域 写在前面 1、基本问题2、拓展问题1.1运行时内存区域
**程序计数器:**记录下一条指令地址,从而实现如顺序执行、循环跳转等等;在多线程中,存在线程切换,程序计数器可以记录当前线程地址,方便线程切换回来以后继续执行 。
**虚拟机栈:**存放编译期可知的各种基本数据类型和对象引用 。
**本地方法栈:**为虚拟机使用到的方法服务 。
**堆:**存放对象实例 。另外堆中还有字符串常量池 。
关于堆中内存区域的分配:堆中分eden区、s区、old区,新生对象被放在eden区,eden区满出发垃圾收集,并采用可达性分析标记,被标记的存活对象被放到s1区,其余对象杀死;再次向eden区放入新生对象,满后,用可达性分析分析eden区和s1区对象存活情况 , 存活的对象被放到s2区,此时s1区清空,如此往复循环 。当对象年龄达到阈值15以后会被放入老年代,另外如果某个年龄超过了s区内存的一半 , 取这个年龄和年龄阈值之间更小的值作为新阈值 。
**方法区:**存放类名、字段、静态成员、方法 。方法区在深入理解java虚拟机这本书中是一个逻辑概念,并不是一个真正意义上的物理分区,真正的物理分区叫做永久代(1.7)/元空间(1.8) 。
? 在使用永久代时,使用两个参数限制它的初始大小和最大大小 , 分别是和,这样可能会抛出,而元空间使用的是直接内存,受本机可用内存的限制,虽然也可能会产生溢出 , 但是几率会小很多,且可以加载的类也更多 。
1.2、 虚拟机对象探秘 1.2.1、对象的创建
**类加载检查:**当遇到new指令时,去常量池检查有没有这个对象的引用,并且检查这个引用代表的类有没有被加载过,如果没有,则进行相应的类加载 。
**分配内存:**为新生对象分配内存——指针碰撞(内存规整);空闲列表(内存不规整) 。
——>内存分配的并发问题(创建对象操作在实际开发中很频繁,需要确保线程安全):
1、CAS+失败重试,保证更新操作原子性
2、TLAB , 为每一个线程预先在 Eden 区分配一块儿内存,JVM 在给线程中的对象分配内存时,首先在 TLAB 分配,当对象大于 TLAB 中的剩余内存或 TLAB 的内存已用尽时,再采用上述的 CAS 进行内存分配
**初始化零值:**为分配到的内存空间初始化零值,保证java代码可以不赋初值使用 。
【春招面试题总结--jvm】**设置对象头:**对对象进行必要的设置 。
**执行init方法:**此时从虚拟机角度 , 对象已经产生了 , 但从程序视角来看对象创建才刚开始,在new指令后紧接一个init方法,把对象按照程序猿的意愿进行初始化 。
1.2.2、对象的内存布局
在虚拟机中,对象在内存中的布局可以分为 3 块区域:对象头、实例数据和对齐填充 。
**对象头:**第一部分用于存储对象自身的运行时数据mark word(哈希码、GC 分代年龄、锁状态标志等等),另一部分是类型指针class point,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例 。
**实例数据:**程序中定义的各种类型的字段内容 。
**对齐填充部分:**仅起占位作用,对象地址大小必须是8字节的整数倍 。
2、JVM垃圾回收 写在前面2.1 堆内存常见分配策略2.2 对象死亡 2.2.1 如何判断一个对象已经无效2.2.2 对象死亡一定会被回收吗
没有被可达性分析标记的对象并不是非死不可,它们处于一个缓刑阶段,要真正宣告死亡还要经历两次标记 。首先是进行可达性分析 , 没有与GC Roots相连的对象将会被第一次标记并进行一次筛?。秆√跫闭飧龆韵笥忻挥斜匾葱蟹椒? ,如果覆盖了会把它放到F-Queue队列里,进行第二次标记 。
2.2.3 关于方法
? 如果一个对象覆盖了 () 方法 , 那么在真正被宣告死亡的时候,至少需要经过两次标记 。第一次被标记的时候会被放在 一个 F-Queue 队列中,() 方法是对象逃脱死亡命运的最后一次机会 。在第二次标记的时候,如果该对象成功与引用链(GC-Roots)上的任何一个对象关联 , 那么它仍然可以存活下来,否则将会被垃圾收集器回收 。
文章插图
2.2.4 Full gc
首先明确三个概念:
Minor GC : 从年轻代空间(包括 Eden 和区域)回收内存 ;
Major GC : 对老年代GC ;
**Full GC :**对整个堆GC, 经常伴随至少一次的Minor GC,但非绝对。FGC管理的内存比较大,效率比较慢,STW时间较长,所以尽量不要出发FGC 。
触发条件:
.gc()
调用.gc()方法会出发full gc.
老年代空间不足
老年代当中存放的对象有以下几种情况:新生代当中存活时间较长(超过一定年龄阈值)的对象、大对象、大数组,如果老年代当中空间不足了,就会出发full gc 。
永久代空间不足
永久代就是我们熟知的方法区,其中存放有类的基本信息、常量、静态变量等数据,当系统当中要加载的类、反射的类、调用的方法太多时,永久代可能会占满,出发full gc.
CMS GC时出现 和 mode
对于采用CMS进行老年代垃圾收集的程序而言,要注意日志中是否有 和 mode 两种情况,他们可能会触发full gc.
2.2.5 再谈引用2.2.6 如何判断一个类是无用类2.3 JVM调优
目标:减少GC时用户线程的暂停时间
方法:JVM参数设置和垃圾收集器选择
2.3.1 关于STW
**为什么:**如果没有STW,假设在程序运行过程中突然发生了gc,通过可达性分析从gc roots找非垃圾对象 , 假设我们找完了,因为没有STW , 线程会继续往下执行,且执行结束 , 而这个时候垃圾收集还没有做完,此时线程所占的内存区域会全部被释放掉,意味着gc roots存储的内存空间也被释放掉了,这个时候之前找出的非垃圾对象就会变成新的垃圾 。堆当中有几十、上百万的对象,我们通过分析找出非垃圾对象 , gc还没有结束对象的状态又变了,变成垃圾对象 , 难道又返回去把这几十万的对象再遍历一次吗,显然不现实 。所以Java开发人员在设计之初 , 索性用了stw,让用户线程暂停?。?把所有的非垃圾对象找出来,把垃圾对象干掉,这样一次gc的时间可能会更快,效率会更高 。
2.3.2 JVM参数调优
背景介绍:
调优前:每个对象60M,一旦有对象进入S区 , 由于超过S区大小的一半,会被存入old区,无法被minor gc回收,根据old区大?。?五六分钟old区就会满发生full gc 。
调优后:把年轻代变大 。
2.3.3 垃圾回收器
1.8默认的垃圾回收:PS+
2.3 垃圾收集算法*3、执行引擎 4、类加载子系统 4.1 加载
将.class文件加载进内存,存放在方法区,然后创建一个class对象,用来封装类的数据结构 。
文章插图
–>类加载器:非数组类由java虚拟机直接创建,数组类由类加载器创建,创建完成后均由类加载器加载 。
1、 (启动类加载器) :最顶层的加载类,负责加载 %%/lib目录下的jar包和类。
2、 (扩展类加载器) :主要负责加载目录 %%/lib/ext 目录下的jar包和类
3、 (应用程序类加载器) : 面向我们用户的加载器 , 负责加载当前应用下的所有jar包和类 。
–>双亲委派模型
java应用程序由若干个.class文件组成,文件之间经常发生调用关系 。而在程序启动时 , class文件并不会一次性加载进内存,而是根据程序需要 , 使用类加载机制()来动态的加载某个class文件到内存当中,只有class文件被加载进内存以后才能被其他class文件调用 。
**加载类的原理:**使用双亲委派模型来搜索类 。每个实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器( )本身没有父类加载器,但可以用作其它实例的的父类加载器 。当一个实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器 试图加载,如果没加载到 , 则把任务转交给 试图加载,如果也没加载到 , 则转交给App进行加载,如果它也没有加载得到的话,则返回给委托的发起者 , 由它到指定的文件系统或网络等URL中加载该类 。如果它们都没有加载到这个类时,则抛出on异常 。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象 。
**jvm如何判定两个class文件相同:**不仅要判定两个类名是否相同,而且要判定是否由同一个加载 。
**优点:**避免重复加载,如果父类已经加载了该类的时候 , 子类就没有必要再加载一次 。也保证了 Java 的核心 API 不被篡改 。
**不想用双亲委派模型怎么办:**使用自定义类加载器的话需要继承类 。如果不想打破双亲委派模型就重写类中的方法,当父类加载器无法加载时,就会通过这个方法加载 。如果想打破就需要重写方法 。
4.2 验证
确保class文件的合法性,不会危害虚拟机自身安全 。
4.3 准备
为类变量分配内存并且设置初始值 。
4.4 解析
将常量池内的符号引用转换为直接引用的过程 。
4.5 初始化
4.6 常见面试题 4.6.1 什么是类加载机制?
虚拟机把描述类的数据从class文件中加载到内存中,并对数据进行检验、转换解析和初始化,最终形成能够被虚拟机直接使用的java类型 。
4.6.2 Java类加载过程
加载–>验证–>准备–>解析–>初始化–>使用–>卸载
4.6.3 什么时候会发生类加载 使用new关键字实例化对象、调用类的静态方法、读取类的静态字段;触发反射机制时;初始化一个类的时候,如果发现其父类还没有进行初始化;虚拟机启动时,用户需要指定一个要执行的主类 , 虚拟机会先初始化这个主类 。4.6.4 jvm加载class文件的原理机制 4.6.5 类加载器的双亲委派模型是什么?可以被打破吗?为什么?
初始化,最终形成能够被虚拟机直接使用的java类型 。
4.6.2 Java类加载过程
加载–>验证–>准备–>解析–>初始化–>使用–>卸载
4.6.3 什么时候会发生类加载 使用new关键字实例化对象、调用类的静态方法、读取类的静态字段;触发反射机制时;初始化一个类的时候,如果发现其父类还没有进行初始化;虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类 。4.6.4 jvm加载class文件的原理机制 4.6.5 类加载器的双亲委派模型是什么?可以被打破吗?为什么?
- 卤味拉面怎么做 卤味拉面怎么做才好吃
- 怎么登陆小米路由器管理界面 如何登陆小米路由器管理界面
- 炮可以吃将吗? 炮可以吃将吗
- 如何判断压缩面膜里有没有荧光剂成分 如何判断压缩面膜里有没有荧光剂
- 目前水产品保鲜新技术主要包括哪些方面
- jovi怎么关闭 vivo手机桌面jovi怎么关闭
- 庐怎么组词 侧怎么组词
- 现烤三明治的做法 现烤三明治如何做
- 修改页面 layui原生框架下,展示、替换图片
- 南安人才社区限价房优惠面积上限