JVM-复习

三、JVM相关

  • GC机制和原理;
  • GC分哪两种,Minor GC 和Full GC有什么区别?什么时候会触发Full GC?分别采用什么算法
  • 什么情况下我们需要破坏双亲委派模型;
  • 常见的JVM调优方法有哪些?可以具体到调整哪个参数,调成什么值?
  • class文件结构是如何解析的;

jvm内存结构

https://www.cnblogs.com/ityouknow/p/5610232.html
程序计数器,私有,表示当前线程执行的字节码的行号。
虚拟机栈,私有:它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
本地方法栈,私有。
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载 的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

堆: Java堆中还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。

jvm模型:jdk1.8 不存在永久代,实现形式是元空间,字符串常量池和静态变量仍然在堆当中,运行时常量池、类型信息、常量、字段、方法被移动都了元空间中。

一个线程有几个栈桢

每个线程一个栈,栈里面是一桢一帧的,每进入一个方法,就往栈里压入一桢,方法运行完就弹出,返回上一桢

新建一个Object对象时,栈帧里的变化过程

https://xie.infoq.cn/article/951fa18f83ba9eaafe2e02997

包装类对象存在哪里?

https://www.cnblogs.com/xiaotian15/p/6971353.html

Java创建的对象都在堆区吗

虚拟机栈一般是用来存储基本数据类型、引用和返回地址的,但是也可以存储实例数据。
涉及到逃逸分析:在编译程序优化理论中,逃逸分析是一种确定指针动态范围的方法——分析在程序的哪些地方可以访问到指针。当一个变量(或对象)在子程序中被分配时,一个指向变量的指针可能逃逸到其它执行线程中,或是返回到调用者子程序。
如果一个子程序分配一个对象并返回一个该对象的指针,该对象可能在程序中被访问到的地方无法确定——这样指针就成功“逃逸”了。如果指针存储在全局变量或者其它数据结构中,因为全局变量是可以在当前子程序之外访问的,此时指针也发生了逃逸。
简单来讲,JVM中的逃逸分析可以通过分析对象引用的使用范围(即动态作用域),来决定对象是否要在堆上分配内存,也可以做一些其他方面的优化。
此时,方法内的对象不逃出作用域时,并且是基本类型组成的(int,double等),就直接在栈上面分配,编译后类似于。

public void method{
//不逃出作用域,因为没有返回值
MyObject o = new MyObject();
o.a=1;
o.b=2
// 编译后变成
// a = 1;
// b = 2;
}
逃逸分析还能用于锁消除:
private void someMethod() {
Object lockObject = new Object();
synchronized (lockObject) {
System.out.println(lockObject.hashCode());
}
}
此时会检测到根本不需要锁,锁清除:
private void someMethod() {
Object lockObject = new Object();
System.out.println(lockObject.hashCode());
}

新建一个Object对象如何与Object类联系起来

对象头里的class ptr https://blog.csdn.net/lkforce/article/details/81128115

OOM和StackOverFlowError的区别

OOM --> https://blog.51cto.com/u_15257216/2861461

类加载机制

JVM里的有几种classloader,为什么会有多种?

  1. 首先,是为了区分同名的类:假定存在一个应用服务器,上面部署着许多独立的应用,同时他们拥有许多同名却不同版本的类库。试想,这时候 jvm 该怎么加载这些类同时能尽可能的避免掉类加载时对同名类的差异检测呢?当然是不同的应用都拥有自己独立的类加载器了。
  2. 其次,是为了更方便的加强类的能力:类加载器可以在 load class 时对 class 进行重写和覆盖,在此期间就可以对类进行功能性的增强。比如添加面向切面编程时用到的动态代理,以及 debug 等原理。怎么样达到仅修改一个类库而不对其他类库产生影响的效果呢?一个比较方便的模式就是每个类库都可以使用独立的类加载器

双亲委派

bootstrap加载JavaHome下的lib目录的文件,

extension加载JavaHome/lib/ext目录的文件,

application加载用户自己的类(classpath上的)

如果一个类可以被委派到基础的ClassLoader加载,就不能让高层的ClassLoader加载

好处: 解决创建同名类问题

打破双亲委派

  1. 自定义类加载器,重写loadClass方法

  2. 使用线程上下文类加载器, Mysql驱动加载的过程

https://www.cnblogs.com/looyee/articles/13954722.html

类卸载,类回收时机

该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如 OSGi、JSP的重加载等,否则通常是很难达成的。
该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

强软弱虚四种引用(强引用,软引用,弱引用,虚引用)

https://blog.csdn.net/qq_15764477/article/details/109366574

ThreadLocal – 弱引用

https://www.cnblogs.com/zz-ksw/p/12684877.html

什么时候用到堆外内存? – 虚引用

https://www.cnblogs.com/reload-sun/p/12216931.html

类加载时机,类加载过程

加载,验证,准备,解析,初始化。深入理解jvm359页。

1)遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始 化,则需要先触发其初始化阶段。能够生成这四条指令的典型Java代码场景有: ·使用new关键字实例化对象的时候。 ·读取或设置一个类型的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外) 的时候。 ·调用一个类型的静态方法的时候。

2)使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需 要先触发其初始化。

3)当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先 初始化这个主类。

5)当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解 析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句 柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。

6)当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有 这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

什么是JIT

当JIT编译启用时(默认是启用的),JVM读入.class文件解释后,将其发给JIT编译器。JIT编译器将字节码编译成本机机器代码。
通常javac将程序源码编译,转换成java字节码,JVM通过解释字节码将其翻译成相应的机器指令,逐条读入,逐条解释翻译。非常显然,经过解释运行,其运行速度必定会比可运行的二进制字节码程序慢。为了提高运行速度,引入了JIT技术。
在执行时JIT会把翻译过的机器码保存起来,以备下次使用,因此从理论上来说,采用该JIT技术能够,能够接近曾经纯编译技术。

常用工具
jps,jstack,jconsole。jps可以查看Java进程,jstack查看死锁,jconsole还可以查看到对象分配情况。具体自己试一下就可以。

垃圾回收机制

垃圾回收算法

https://www.jianshu.com/p/4bdc443f5c92

Jdk8默认的垃圾回收器

Parallel Scavenge + Parallel Old

jdk 1.9 G1

什么时候会FullGC

调用system.gc();未指定老年代和新生代大小,堆伸缩时会fullgc,所以要配置-Xmx和-Xms;老年代空间不足;统计得到的minor gc存活对象超过了老年代剩余空间;jdk1.7之前的永久代满了

GCROOT有哪些

在Java技术体系里面,固定可作为GC Roots的对象包括以下几种:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的 参数、局部变量、临时变量等。

  • 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。

  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。

  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。

  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如 NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。 ·所有被同步锁(synchronized关键字)持有的对象。

  • 反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

G1收集器-深入理解jvm148页

G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。在jdk9就已经是默认的垃圾收集器了。

基于Region的堆内存布局收集。 G1不再坚持固定大小以及固定数量的 分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的 Region采用不同的策略去处理,这样无论是新创建的对象还是已经存活了一段时间、熬过多次收集的 旧对象都能获取很好的收集效果。 Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了一个 Region容量一半的对象即可判定为大对象。 而对于那些超过了整个Region容量的超级大对象, 将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代 的一部分来进行看待.
让G1收集器去跟踪各个Region里面的垃 圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一 个优先级列表,每次根据用户设定允许的收集停顿时间(使用参数-XX:MaxGCPauseMillis(项目里面也是200)指定,默 认值是200毫秒),优先处理回收价值收益最大的那些Region,这也就是“Garbage First”名字的由来。 这种使用Region划分内存空间,以及具有优先级的区域回收方式,保证了G1收集器在有限的时间内获 取尽可能高的收集效率 .
初始标记(短暂停顿,可以忽略)-并发标记(可以与用户线程并发执行)-最终标记(短暂暂停用户线程)-筛选回收(必须暂停用户线程)

CMS、G1区别

https://juejin.cn/post/6844903974676463629

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值