JVM相关

  1. 入门部分
    1. 为什么要学习JVM?

答:有助于我们从平台的角度提高解决问题的能力:防治内存泄露\优化线程锁的使用\科学进行垃圾回收\提高系统吞吐量\降低延迟,提高其性能; 并且JVM是中高级程序员必备能力之一

    1. 你了解哪些JVM产品?

答:JVM有包括 SUN公司研发的HotSpot VM 是现在官方的JVM,现在我们下载JDK后自带的虚拟机;JRockit VM ;J9 VM IBM内部使用; TaoBaoJVM 阿里基于OpenJDK开发的AlibabaJDK

    1. JVM的构成有哪几部分?

答:JVM包括:类加载系统--ClassLoader System 负责加载类到内存中 ;运行时数据区--Runtime Data Area  负责存储数据信息包括对象方法等; 执行引擎 --Execution Engine 负责解释执行字节码,执行GC操作等;本地库接口--Native Interface 负责 融合不同的编程语言为java所用

  1. 类加载部分
    1. 你知道哪些类加载器?

答:类加载器包括: 应用程序类加载器--AppClassLoader 也叫做系统类加载器,用于加载系统路径中制定的类库中的类; 扩展类加载器--ExtClassLoader 系统类加载器的父加载器 ,用于加载jre/lib/ext目录下的类,启动类加载器或根类加载器--BootstrapClassLoader 用于加载jre/lib下面的类库, 底层由C++实现

    1. 什么是双亲委派类加载模型?

答:java虚拟机对class文件采用的是按需加载的方式,通过向上询问是否加载,向下尝试是否可加载的方式进行操作,具体实现:当类加载器收到请求,不会直接加载,而是向上一次询问,最终到达启动类加载器,然后由启动类加载器开始判断是否能加载,如果能就加在,如果不能就向下委派,这种模式叫做双亲委派机制,当然如果向下委派到最后的系统加载器,如果也无法加载就会抛出异常

    1. 双亲委派方式加载类有什么优势、劣势?

答: 优势:通过双亲委派机制可以避免类的重复加载;劣势:每一类的加载都需要向上询问,向下委派,加载的效率低,同事如果是自己写的类与系统类同名,也会导致加载不成功,系统默认已加载

    1. 描述一些类加载时候的基本步骤是怎样的?

答:类加载的基本过程:首先通过类的全限定名获取定义的而进行字节流-将这个字节流所代表的的静态存储结构转化为方法区的因行使数据结构,在java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中的这些数据的访问入口.

    1. 什么情况下会触发类的加载?

答:类的加载时机:创建类的实例也就是new对象时; 访问类的静态变量;访问类的静态方法;反射机制;初始化一个类的子类;虚拟机启动时定义了main方法的类

    1. 类加载时静态代码块一定会执行吗?

答:类加载的过程中静态代码块不一定执行,静态代码块是否执行依托于加载的方式,

    1. 如何理解类的主动加载和被动加载?

答:主动加载是自己通过类加载器进或者反射机制进行主动加载;被动加载主要是:当访问静态成员,实例化类,或子类的实例化时会加载父类

    1. 为什么要自己定义类加载器,如何定义?

答:自定义类加载器可以打破双亲委派模型, 通过继承ClassLoader 并重写期中的LoadClass方法来实现

  1. 字节码增强部分
    1. 为何要学习字节码?

答:对开发人员来说,了解字节码有主意更准确,直观的理解java语言中更深层次的东西,如果通过字节码可以直观看到Volatile关键字如何在自驾吗上升小.另外字节码增强结束在Spring AOP ,各种ORM框架.热部署中的应用屡见不鲜,深入理解原理对我们很有帮助,同时由于JVM 规范的存在i,只要最终可以生成符合规范的字节码就可以在JVM上运行,这也是给了各种运行在JVM上的语言的一种契机,可以扩展java所没哟肚饿特性或实现各种语法的综合

    1. 如何解读字节码内容?

答: 解读方式:可以通过notepad++软件中的HEX-Editor插件直接打开字节码文件的16进制文件直接读取;利用java 的 javap -verbase 文件名.class 命令进行反编译; 也可以利用jclasslib差价进行查看,这个是idea中的插件,需要自己下载,在View菜单栏总选show bytecode with jclasslib就看对选中的类进行查看,很直观

    1. 字节码内容由哪几部分构成?

答:字节码内容包括如下几个部分:魔术-magic ; 次版本号-minor_version ;主版本号-major_version; 常量池计数器-constant_pool_count; 常量池-constant_pool[constant_pool_count-1];类的访问标志-access_flags ;当前类名索引值-this_class;父类名索引值-super_class; 接口计数-interfaces_count;接口数组-interfaces[interfaces_count]; 成员变量计数-fields_count;方法计数-methods_count;方法数组-methods[methods_count];属性计数-attributes_count; 属性数组-attributes[attributes_count]

    1. 什么是字节码增强?

答:字节码增强技术相当于是一把打开运行时JVM的钥匙,利用它可以显示对现有字节码进行修改或者动态生成新的字节码,进行对运行过程中的程序进行修改,实现热部署,也可以跟踪JVM运行中程序的状态,进行性能诊断;此外,我们平时所使用的的动态代理,AOP也与字节码增强密切相关,他们实质上还是利用各种手段生成符合规范的字节码文件

    1. 为什么要进行字节码增强?

答:掌握字节码增强技术以后可以高效的定位并快速修复一些棘手的问题,也可以在开发中减少冗余代码,大大提高开发效率

    1. 你了解哪些字节码增强技术?

答:ASM技术: ASM core API 通过ClassReader:用于读取已经编译好的字节码文件,ClassWriter:用于重新构建编译后的类,例如修改类名,属性以及方法,也可以生成新的类的字节码文件;ClassVisitor  ASM中对于字节码文件中不同的区域有不同的Visitor,比如用于访问方法的MethodVisitor ,用于访问类变量的FieldVisitor,用于访问注解的AnnotationVisitor等,为了实现AOP,充电要使用MethodVisitor

   Javassist计数:是一个用于分析,编辑和创建Java字节码的类库,相比ASM的指令层此操作自己吗会更加简单直观, Javassist中最重要的是ClassPool 时CtClass对象的容器,CtClass 编译时类信息,特使一个class文件在字节码中的抽闲表现形式,CtMethod 对应类中的方法.CtField 对应类在中的属性

   Java Agent技术:是java Instrumentation API的一部分,可以侵入运行在JVM上的应用程序,进而修改应用程序中各种类的字节码;主要提供两个接口: Instrumentation 提供向java中插入代码的服务,ClassFileTransformer yo9ngyu转换类文件

    1. 什么是热替换以及如何实现?

答:热替换就是对运行在JVM上的程序进行侵入式替换, 通过Java Agent技术可以实现

  1. JVM运行内存部分
    1. JVM运行内存是如何划分的

答: 运行时内存划分:程序计数器;java栈和本地方法栈;堆内存;方法区内容

    1. JVM中的程序计数器用于做什么?

答: 程序计数器也叫PC寄存器,是一块较小的内存空间,用来存储指向吓一跳指令的地址,也可以看做是当前线程执行的字节码的行号指示器,在虚拟机的概念模型里,字节码解析器的工作是通过改变这个计数器的值来选取下一条要执行的字节码制定,分支\循环\跳转\异常处理\线程恢复等基础功能都需要依赖这个计数器来完成

    1. JVM虚拟机栈的结构是怎样的?

答:构成包括:局部变量表-Local Variables ;操作数栈-Operand Stack 或者表达式栈; 动态链接-Dynamic Linking  或指向运行时常量池的方法引用; 方法返回地址-ReturnAddress 或方法正常退出或异常退出的定义;

    1. JVM虚拟机栈中局部变量表的作用是什么?

答:局部方法表也叫做局部变量素组或本地变量表,用于存放方法参数和方法内部定义的局部变量信息,在java程序被编译为Class文件是,就已经确定每个方法所需局部变量表的大小,局部变量表以变量槽为最小单位,每个变量槽可以存放一个32为以内的数据类型,故每个变量槽都应该能放boolean,byte.char.short,int.float,refrence,或returnAddress类型的数据,对于long,double梁总会占用两个变量槽

    1. JVM虚拟机栈中操作数栈的做用时什么?

答:每个独立的栈帧除了包含局部变量表以外,还包含一个后进先出的操作数栈,操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈和出栈

    1. JVM堆的构成是怎样的?

答:堆内存分为年轻代和老年代,年轻代又分为Eden和两个Survivor区

    1. Java对象分配内存的过程是怎样的?

答:编译器通过逃逸分析,确定对象是在栈上分配还是在堆上分配; 如果是在堆上分配,则首先检测是否可以在TLAB上直接分配,如果TLAB上无法直接分配则在Eden加锁区进行分配,如果Eden区无法存储对象,则执行YongGC,如果YongGc之后Eden区仍然不足以存储对象,则直接分配在老年代

    1. JVM年轻代幸存区设置的比较小会有什么问题?

答:伊甸园区被回收时,对象要拷贝到幸存区,假如幸存区比较小,拷贝的对象比较大,对象就会直接存储到老年代,这样会增加老年代GC的频率。而分代回收的思想就会被弱化。

    1. JVM年轻代伊甸园区设置的比例比较小会有什么问题?

答:伊甸园设置的比较小,会增加GC的频率,可能会导致STW的时间边长,影响系统性能。

    1. JVM堆内存为什么要分成年轻代和老年代?

答:为了更好的实现垃圾回收

    1. 如何理解JVM方法区以及它的构成是怎样的?

答:方法区是一个种规范,用于存储已被虚拟机加载的类信息,敞亮,静态变量,即时编译后的代码等数据,不同jdk,方法区的实现不同,HotSpot虚拟机在JDK8宗使用Native Memory来实现方法区,在JDK8的HotSopt中虚拟机中方法区的落地实现时元数据区,但是元数据区并不在虚拟机中,而是使用本地内存,因此默认情况下,元空间的大小仅受本地内存限制,但可以通过一些参数来制定元空间的大小;方法区是一种规范:用于存储已被虚拟机加载的类信息,敞亮,静态变量,即时编译后的代码等数据,类信息包括对每个加载的类型(类class、接口interface、枚举enum、注解annotation)以及属性和方法信息,常量信息可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型

    1. 什么是逃逸分析以及可以解决什么问题?

答:逃逸分析一种数据分析算法,基于此算法可以有效减少Java对象在堆内存中的分配。Hotspot虚拟机的编译器能够分析出一个新对象的引用范围,然后决定是否要将这个对象分配到堆上。例如:当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸;当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸。

    1. 何为内存溢出以及导致内存溢出的原因?

答:内存中剩余的内存不足以分配给新的内存请求就会内存溢出。内存溢出可能直接导致系统崩溃。内存泄漏是导致内存溢出的一种原因,但内存溢出不全是由内存泄漏引起的,还可能是:创建的对象太大导致堆内存溢出;创建的对象太多导致堆内存溢出;方法出现了无限递归调用导致栈内存溢出;方法区内存空间不足导致内存溢出。

    1. 何为内存泄漏以及内存泄漏的原因是什么?

答:动态分配的内存空间,在使用完毕后未得到释放,结果导致一直占据该内存单元,直到程序结束。这个现象称之为内存泄漏。因此良好的代码规范,可以有效地避免这些错误。大量使用静态变量(静态变量与程序生命周期一样);IO/连接资源用完没关闭(记得执行close操作);内部类的使用方式存在问题(实力内部类或默认引用外部类对象);缓存(Cache)应用不当(尽量不要使用强引用);ThreadLocal应用不当(用完记得执行remove操作)

    1. JAVA中的四大引用你知道多少?

答:在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用;Java中根据其生命周期的长短,将引用分为4类。

1 强引用

特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。

2 软引用

特点:软引用通过SoftReference类实现。 软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。

应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。

3 弱引用

弱引用通过WeakReference类实现。 弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

应用场景:弱应用同样可用于内存敏感的缓存。

4 虚引用

特点:虚引用也叫幻象引用,通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

ReferenceQueue queue = new ReferenceQueue ();

PhantomReference pr = new PhantomReference (object, queue);

程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取一些程序行动。

应用场景:可用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知。

  1. JVM垃圾回收部分
    1. 何为GC以及为和要GC?

GC(Garbage Collection)称之为垃圾回收,是对内存中的垃圾对象,采用一定的算法进行内存回收的一个动作。比方说,java中的垃圾回收会对内存中的对象进行遍历,对存活的对象进行标记,其未标记对象可认为是垃圾对象,然后基于特定算法进行回收。

    1. 你知道哪些GC算法?

标记清除:标记清除(Mark-Sweep)算法分为“标记”和“清除”阶段,它首先会标记出内存中所有不需要回收的对象,然后从内存中清除所有未标记的对象。

标记复制:标记复制(Mark-Copy)算法是将内存分为大小相同的两块,当这一块使用完了,就把当前存活的对象复制到另一块,然后一次性清空当前区块。

标记整理:标记整理清除(Mark-Sweep-Compact)算法结合了“标记-清除”和“复制”两个算法的优点。第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把存活对象“压缩”复制到堆的其中一块空间中,按顺序排放。第三阶段清理掉存活边界以外的全部内存空间。

    1. JVM中有哪些垃圾回收器?

Serial收集器

Serial GC是最古老也是最基本的收集器,但是现在依然广泛使用,JAVA SE5和JAVA SE6中客户端虚拟机采用的默认配置。

1. Serial GC(串行收集器)应用特点:

内部只使用一个线程执行垃圾回收(不能充分利用CPU的多核特性),无法并行化。

GC时所有正在执行的用户线程暂停并且可能会产生较长时间的停顿(Stop the world)。

2. Serial GC(串行收集器)场景应用:

一般可工作在JVM的客户端模式。

适用于CPU个数或核数较少且内存空间较小(越大可能停顿时间越长)的场景。

3. Serial GC(串行收集器)算法应用

新生代使用 mark-copy(标记-复制) 算法(新生代存活对象较少)。

老年代使用 mark-sweep-compact(标记-清除-整理)算法(老年代对象回收较少,容易产生碎片)。

Parallel收集器

Parallel 收集器为并行收集器,它可利用多个或多核CPU优势实现多线程并行GC操作,其目标是减少停顿时间,实现更高的吞吐量(Throughput)。

1. Parallel GC(并行收集器)应用特点:

可利用CPU的多核特性执行多线程下的并行化GC操作。

GC期间, 所有 CPU 内核都在并行清理垃圾, 所以暂停时间较短。

最大优势是可实现可控的吞吐量与停顿时间。

2. Parallel GC(并行收集器)场景应用:

GC操作仍需暂停应用程序(也有可能暂停时间比较长,因为GC阶段不能被打断),所以不适合要求低延迟的场景。

因其高吞吐GC(throughput GC)量的特性,适用于后台计算、后台处理的弱交互场景而不是web交互场景。

3. Parallel GC(并行收集器)算法应用:

在年轻代使用标记-复制(mark-copy)算法,对应的是Parallel Scavenge收集器。

在老年代使用标记-清除-整理(mark-sweep-compact)算法,对应的是Parallel Old收集器。

CMS 收集器

CMS的官方名称为 “Mostly Concurrent Mark and Sweep Garbage Collector”,其设计目标是追求更快的响应时间。

1. CMS (并发收集器)应用特点:

使用空闲列表(free-lists)管理内存空间的回收,不对老年代进行碎片整理,减少用户线程暂停时间。

在标记-清除阶段的大部分工作和用户线程一起并发执行。

最大优点是可减少停顿时间(可提高服务的响应速度),最大缺陷是老年代的内存碎片。

2. CMS (并发收集器)场景应用:

应用于多个或多核处理器,目标降低延迟,缩短停顿时间,响应时间优先。

CPU受限场景下,因与用户线程竞争CPU,吞吐量会减少。

3. CMS (并发收集器)算法应用:

年轻代采用并行方式的 mark-copy (标记-复制)算法。

老年代主要使用并发 mark-sweep (标记-清除)算法。

4. CMS (并发收集器)关键步骤分析:

初始标记(initial mark)阶段标记一下GC Roots能直接关联到的对象,速度很快。

并发标记(concurrent mark)阶段就是进行GC Roots Tracing的过程,从直接关联对象遍历所有可达对象,然后进行标记。

重新标记(final remark)阶段要修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。

并发清除(concurrent sweep)阶段与应用程序并发执行,不需要STW停顿。目的是删除未使用的对象,并收回他们占用的空间。

并发重置 (concurrent Reset) 阶段与应用程序并发执行,重置CMS算法相关的内部数据,同时GC线程切换到用户线程。

G1收集器

G1(Garbage-First )收集器是一种工作于服务端模式的垃圾回收器,主要面向多核,大内存的服务器。G1 在实现高吞吐的同时,也最大限度满足了GC 停顿时间可控的目标。在Oracle JDK7 update 4 后续的版本中已全面支持G1 回收器功能。G1收集器主要为有如下需求的程序设计:

可以像CMS 收集器一样能同时和应用线程一起并发的执行。

减少整理内存空间时的停顿时间。

要满足可预测的GC停顿时间需求。

不能牺牲太多的吞吐性能。

未来 G1 计划要全面取代CMS。G1相比CMS有更多的优势,G1是压缩型收集器,可以实现更有效的空间压缩,消除大部分潜在的内存碎片问题。G1提供了更精准的可预测的垃圾停顿时间设置,可满足用户在指定垃圾回收时间上的需求。

在G1中,堆不再分成连续的年轻代和老年代空间,而是划分为多个(通常是2048个)可以存放对象的小堆区(smaller heap regions)。每个小堆区都可能是Eden区, Survivor区或者Old区. 在逻辑上, 所有的Eden区和Survivor区合起来就是年轻代, 所有的Old区拼在一起那就是老年代,

  1. 服务频繁fullgc,younggc次数较少,可能原因?

full gc 触发条件是 老年代空间不足, 所以追因的方向就是导致 老年代空间不足的原因:
大量对象频繁进入老年代 + 老年代空间释放不掉

系统并发高、执行耗时过长,或者数据量过大,导致 young gc频繁,且gc后存活对象太多,但是survivor 区存放不下(太小 或 动态年龄判断) 导致对象快速进入老年代 老年代迅速堆满

发程序一次性加载过多对象到内存 (大对象),导致频繁有大对象进入老年代 造成full gc

存在内存溢出的情况,老年代驻留了大量释放不掉的对象, 只要有一点点对象进入老年代 就达到 full gc的水位了

元数据区加载了太多类 ,满了 也会发生 full gc

堆外内存 direct buffer memory 使用不当导致

也许, 你看到老年代内存不高 重启也没用 还在频繁发生full gc, 那么可能有人作妖,在代码里搞执行了 System.gc();

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值