JVM八股文,面试会被问到什么?都在这里啦 ~

news2024/12/23 18:30:20

目录

1、JVM内存划分

1.1、程序计数器(Program Counter Register)

1.2、方法区(Method Area)

1.3、本地方法栈(Native Method Stacks)

1.4、虚拟机栈(JVM Stacks)

1.5、Java堆(Heap)

2、JVM类加载

2.1、加载过程

2.2、类加载流程

2.3、类加载器【双亲委派模型】

3、JVM的垃圾回收

3.1、如何确定对象已死

3.1.1、回收哪些内存

3.1.2、基于引用计数找垃圾(Java不采取该方案)

3.1.3、基于可达性分析找垃圾(Java采取方案)

3.2、垃圾回收算法

3.3.1标记-清除算法

3.3.2标记-复制算法

3.3.3标记-整理算法

3.3.4分代回收

3.3、垃圾收集器

1)、Serial收集器

2)、ParNew收集器

 3)、CMS收集器

 4)、G1收集器(唯一一款全区域的垃圾回收器)


1、JVM内存划分

        JVM区域包括以下几个:程序计数器,栈,堆,方法区,图中的元数据区可以理解为方法区 【1.8之后搞了个元数据区,在这之前都是方法区的】,毕竟JVM有很多版本,不同版本的运行时区域划分也不一样。

运行时区域划分

1.1、程序计数器(Program Counter Register)

        它的作用就是记录当前线程所执行的位置。 这样,当线程重新获得CPU的执行权的时候,就直接从记录的位置开始执行,分支、循环、跳转、异常处理也都依赖这个程序计数器来完成。

1.2、方法区(Method Area)

方法区也是一块被重点关注的区域,主要特点如下:

  • 线程共享区域,因此这是线程不安全的区域。

  • 它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  • 当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

1.3、本地方法栈(Native Method Stacks)

        本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

        虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

1.4、虚拟机栈(JVM Stacks)

  • Java虚拟机栈是线程私有的,每一个线程都有独享一个虚拟机栈,它的生命周期与线程相同。

  • 虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

  • 存放基本数据类型(boolean、byte、char、short、int、float、long、double)以及对象的引用(reference类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。

  • 这个区域可能有两种异常:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩,当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

1.5、Java堆(Heap)

栈管运行,堆管存储。则虚拟机栈负责运行代码,而虚拟机堆负责存储数据。

Java堆区具有下面几个特点:

  • 存储的是我们new来的对象,不存放基本类型和对象引用。

  • 由于创建了大量的对象,垃圾回收器主要工作在这块区域。

  • 线程共享区域,因此是线程不安全的。

  • 能够发生OutOfMemoryError。

其实,Java堆区还可以划分为新生代和老年代,新生代又可以进一步划分为Eden区、Survivor 1区、Survivor 2区


2、JVM类加载

2.1、加载过程

如果JVM想要执行这个.class文件,我们需要将其装进一个类加载器中,它就像一个搬运工一样,会把所有的.class文件全部搬进JVM里面来

 知识点:

  • Java文件经过编译后变成了.class字节码文件
  • 字节码文件通过类加载器被搬运到JVM虚拟机中
  • 虚拟机主要的5大部分:

         方法区、堆都是线程共享区域,有线程安全问题;栈、本地方法栈、计数器都是线程独享区域,不存在线程安全问题;而JVM的调优主要是围绕堆、栈两大块进行的。

  • 总结来看,JVM主要通过分为以下4个部分,来执行Java程序的,分别是:类加载器(ClassLoader)、运行时数据区(Runtime Data Area)、执行引擎(Execution Engine)、本地库接口(Native Interface)

2.2、类加载流程

        类加载的过程包括了加载、验证、准备、解析、初始化5个阶段。在这5个阶段中,加载、验证、准备和初始化这4个阶段发生的顺序是确定的,而解析阶段就不一定了,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始的,而不是按顺序进行或完成的,因为这些阶段通常都是互相交叉的混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段 

  •  加载:查找并加载类的二进制数据;在Java堆中也创建一个java.lang.Class类的对象,作为方法区这个类的各种数据的访问入口;
  • 连接:连接包含了三个部分:验证、准备、初始化   
  • 验证:文件格式、元数据、字节码、符号引用验证
  • 准备:为类的静态变量分配内存,并将其初始化为默认值【例:public static int a = 12;它的默认初始值为0而不是12】
  • 解析:把类中的符号引用转换为直接引用,也就是初始化常量的过程
  • 初始化:为类的静态变量赋予正确的初始值,初始化阶段就是执行类构造器方法的过程

        这里真正的对类对象进行初始化,特别是静态成员。类加载过程中是在执行某方法(如main方法)之前执行的,类加载的时候会进行静态代码块的执行,想要创建实例,必然先得类加载,静态代码块只会执行一次,构造方法与普通代码块每次实例对象都会执行,并且普通代码块比静态代码块先执行

        所以可以得到结论,静态的代码块,普通代码块,构造方法执行顺序为:静态代码块--普通代码块--构造方法

  • 使用:new出对象程序中使用
  • 卸载:执行垃圾回收

2.3、类加载器【双亲委派模型】

 双亲委派模型是类加载中的一个环节,属于Loading阶段,它是描述如何根据类的全限定名找到class文件的过程。

在JVM里面提供了一组专门的对象,用来进行类的加载,即类加载器,当然既然双亲委派模型是类加载中的一部分,所以其所描述找.class文件的过程也是类加载器来负责的

但是想要找全class文件可不容易,毕竟.class文件可能在jdk目录里面,可能在项目的目录里面,还可能在其他特定的位置,因此JVM提供了多了类加载器,每一个类加载负责在一个片区里面找,毕竟分工明确,才能事半功倍

默认的类加载器主要有三个:

  • BootStrapClassLoading:负责加载标准库里面的类,如:String,Random,Scanner等
  • ExtensionClassLoader:负责加载JDK扩展的类,现在基本上很少使用了
  • ApplicationClassLoader:负责加载当前项目目录中的类

        除了默认的几个类加载器,程序员还可以自定义类加载器,来加载其他目录的类,如Tomcat就自定义了类加载器,用来专门加载webapp目录中的.class文件,但是自定义的类加载器未必要遵守双亲委派模型,毕竟你在自己特定的目录下还没有找到对应的.class文件,再去标准库去找基本也是未果,Tomcat中的自定义的类加载器就没有遵守双亲委派模型

        而双亲委派模型就描述了类加载过程中的找目录的环节,它的内容如下:

        如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此。

        因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载(去自己的片区搜索)。

举两个栗子:第一个,我们要去找标准库里面的String.class文件,它的过程大致如下:

  • 首先ApplicationClassLoader类收到类加载请求,但是它先询问父类加载器是否加载过,即询问ExtensionClassLoader类是否加载过。
  • 如果ExtensionClassLoader类没有加载过,请求就会向上传递到ExtensionClassLoader类,然后同理,询问它的父加载器BootstrapClassLoader是否加载过。
  • 如果BootstrapClassLoader没有加载过,则加载请求就会到BootstrapClassLoader加载器这里,由于BootstrapClassLoader加载器是最顶层的加载器,它就会去标准库进行搜索,看是否有String类,我们知道String是在标准库中的,因此可以找到,请求的加载任务完成,这个过程也就结束了。
     

第二个栗子,我要加载搜索项目目录中的Test类,过程如下:

  • 首先ApplicationClassLoader类收到类加载请求,但是它先询问父类加载器是否加载过,即询问ExtensionClassLoader类是否加载过。
  • 如果ExtensionClassLoader类没有加载过,请求就会向上传递到ExtensionClassLoader类,然后同理,询问它的父加载器BootstrapClassLoader是否加载过。
  • 如果BootstrapClassLoader没有加载过,则加载请求就会到BootstrapClassLoader加载器这里,由于BootstrapClassLoader加载器是最顶层的加载器,它就会去标准库进行搜索,看是否有Test类,我们知道Test类不在标准库,所以会回到子加载器里面搜索。
  • 同理,ExtensionClassLoader加载器也没有Test类,会继续向下,到ApplicationClassLoader加载器中寻找,由于ApplicationClassLoader加载器搜索的就是项目目录,因此可以找到Test类,全过程结束。

当然,如果在ApplicationClassLoader还没有找到,就会抛出异常。

 总的来说,双亲委派模型就是找class文件的过程,只是名字挺高大上的,其实也没啥。

 1

双亲委派模型的优点:

  • 当自定义类与标准库中的类重名时,一定会加载标准库中的那个类,保证了Java的核心API不会被篡改。
  • 使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。
  • 避免重复加载类:比如 A 类和 B 类都有一个父类 C 类,那么当 A类 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了。
     

3、JVM的垃圾回收

3.1、如何确定对象已死

3.1.1、回收哪些内存

        我们知道我们运行时,内存分为四个区,分别是程序计数器,栈,堆,方法区。
对于程序计数器,它占据固定大小的内存,不涉及释放,那么也就用不到GC;对于栈空间,函数执行完毕,对应的栈帧自动释放了,也不需要GC;对于方法区,主要进行类加载,虽然需要进行"类卸载",此时需要释放内存,但是这个操作的频率是非常低的;最后对于堆空间,经常需要释放内存,是最需要进行GC的。

        在堆空间,内存的分布有三种,一是正在使用的内存,二是未使用且未回收的内存,三是未分配的内存,那内存中的对象,也有三种情况,对象内存全部在使用(相当于对象整体全部在使用),对象的内存部分在使用(相当于对象的一部分在使用),对象的内存不使用(对象也就使用完毕了),对于这三类对象,前两类不需要回收,最后一类需要回收。

 

        所以,垃圾回收的基本单位是对象,而不是字节,对于如何找到垃圾,常用有引用计数法与可达性分析法两种方式。

3.1.2、基于引用计数找垃圾(Java不采取该方案)

         所谓基于引用计数判断垃圾,就是给每一个对象带上一个计数器,来记录该对象被多少个引用变量所指,如果这个计数器的值为0则表示该对象需要回收,比如有一个Test对象,它被两个引用所指,所以这个Test对象所带计数器的值就是2

 

        如果上述的伪代码是在一个方法中,待方法执行完毕,方法中的局部引用变量被销毁,那么Test对象的引用计数变为0,此时就会被回收。

由此可见,基于引用计数的方案非常简单高效并且可靠,但是它拥有两个致命缺陷:

  • 当对象的内存大小较小时,由于每个对象都需要一个计数器,因此空间利用率较低。
  • 存在循环引用的问题,会出现对象既不使用也不释放的情况。

第一点好理解,就是当计数器与对象所需内存差不多的情况下,空间利用率只有50%,并不高。
第二点,难理解一点,下面我们来举例子进行分析。

class Test {
	Test t = null;
}

//main方法中:
Test t1 = new Test();
Test t2 = new Test();
t1.t = t2;
t2.t = t1;

执行上述伪代码,运行时内存图如下:

 

然后,我们把变量t1t2置为null,伪代码如下:

//伪代码:
t1 = null;
t2 = null;

 执行完上面伪代码,运行时内存图如下:

         根据图可知,两个对象的属性相互指向另一个对象,使得计数器的值都为1,由于对象外界没有指向这两个对象的引用,于是这两个对象处于既不被使用,也不被释放的尴尬场景当中,这就是循环引用问题。

3.1.3、基于可达性分析找垃圾(Java采取方案)

        所谓可达性分析就是通过额外的线程,对整个内存空间的对象进行扫描。但扫描不是盲扫,先会找到一些起始位置GCRoots,从该位置开始,以类似深度优先搜索的方式去找对象,它会对所有可以找到的对象进行标记,没有找到的对象自然也就没有标记,那这部分有标记的对象是可达的,未被标记的对象是不可达的,未被标记的对象就会被JVM视为垃圾进行回收。
1

 

对于这个GCRoots,它来自:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,例如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
  • 常量池中引用所指向的对象。
  • 方法区中静态成员所指向的对象。
  • 所有被同步锁(synchronized关键字)持有的对象。
     

3.2、垃圾回收算法

垃圾回收的算法最常见的有以下几种:

标记-清除算法
标记-复制算法
标记-整理算法
分代回收算法
(本质就是综合上述算法,在堆的不同区采取不同的策略)

3.3.1标记-清除算法

        标记其实就是可达性分析的过程,在可达性分析的过程中,会标记可达的对象,其他 不可达的对象,都会被视为垃圾进行回收。

比如经过一轮标记后,标记状态如图:

 回收后,内存状态如图:

 

        我们发现,内存是释放了,但是回收后,未分配的内存空间有点“散”啊,我们知道申请内存的时候得到的内存是连续的,所以说,由于未分配的内存是碎片化的,假设你的主机有1GB为分配的内存,但是这些内存是碎片形式存在的,当申请500MB内存的时候,可能会申请失败,毕竟不能保证有一块大于500MB的连续内存空间,这也是标记-清除算法的缺陷。

3.3.2标记-复制算法


        为了解决标记-清除算法所带来的内存碎片化的问题,引入了复制算法。

        它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。如果内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况。

        复制算法的第一步还是要通过可达性分析进行标记,得到那一部分需要进行回收,那一部分需要保留,不能回收。

        标记完成后,会将还在使用的内存连续复制到另外一块等大的内存上,这样得到的未分配内存一直都是连续的,而不是碎片化的。

 回收后,复制算法得到的未分配空间是连续的,完美地弥补了清除算法的缺陷。

 

但是,复制算法也有缺陷:

  • 空间利用率低。
  • 如果可回收的内存少,需保留的内存大,复制的开销也大。

3.3.3标记-整理算法

        标记-整理算法针对复制算法做出进一步改进。其中的标记过程仍然与“标记-清除”算法一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。

标记回收前的内存图:

        然后,将存活对象按照某一顺序(比如从左到右,从上到下的顺序)拷贝到非存活对象的内存区域,得到了以下回收后的内存分布图:

 

 

解决了标记-复制算法空间利用率低的问题,但是复制的开销问题并没有得到解决。

3.3.4分代回收

        上述的回收算法都有缺陷,分代回收就是将上述三种算法结合起来分区使用,分代回收会针对对象进行分类,以熬过的GC扫描轮数作为“年龄”,然后针对不同年龄采取不同的方案。

        我们知道GC主要是回收堆上的无用内存,我们先来了解一下堆的划分,堆包括新生代(Young)、老年代(Old),注意这个名称不是固定的,在IBM J9虚拟机中对应称为婴儿区(Nursery)和长存区(Tenured),名字不同但其含义是一样的。而新生代包括一个伊甸区(Eden)与两个幸存区(Survivor,分代回收算法就会根据不同的代去采取不同的标记-xx算法。
堆

        在新生代,包括一个伊甸区与两个幸存区,伊甸区存储的是未经受GC扫描的对象,也就是刚刚创建的对象。

        幸存区存储了经过若干轮存储的对象,通过实际经验得出,新生代的对象具有“朝生夕灭”的特点,也就是说只有少部分的伊甸区对象才能熬过第一轮的GC扫描,所以到幸存区的对象相比于伊甸区少的多,正因为大部分新生代的对象熬不过JVM第一轮扫描,所以伊甸区与幸存区的分配比例并不是1:1的关系,HotSpot虚拟机默认一个Eden和一个Survivor的大小比例是8∶1,正因为新生代的存活率较小,所以新生代使用的垃圾回收算法为标记-复制算法最优,毕竟存活率越小,对于标记-复制算法,复制的开销也就很小。

        不妨我们将第一个Survivor称为活动空间,第二个Survivor称为空闲空间,一旦发生GC,将10%的活动区间与另外80%中存活的对象复制到10%的空闲空间,接下来,将之前90%的内存全部释放,以此类推。

        在后续几轮GC中,幸存区的对象在两个Survivor中进行标记-复制算法。

        在继续持续若干轮GC后,幸存区的对象就会被转移到老年代,老年代中都是年龄较老的对象,根据经验,一个对象越老,继续存活的可能性就越大,因此老年代的GC扫描频率远低于新生代,所以老年代采用标记-整理的算法进行内存回收,毕竟老年代存活率高,对于标记-整理算法,复制转移的开销很低。

3.3、垃圾收集器

1)、Serial收集器

这一部分,我们了解即可,首先有请历史最悠久的Serial收集器(新生代收集器,串行GC)与 Serial Old收集器(老年代收集器,串行GC)登场,这两类收集器前者是新生代收集器,后者是老年代收集器,采用串行GC的方式进行垃圾收集,由于串行GC开销较大,会产生较严重的STW。

 

STW是什么?

        Stop The World (STW),你可以理解为你打游戏的时候,你的xxx来干xxx,使得你不得不中断游戏,这段中断的时间就相当于STW,或者你理解为由于设备原因使得你打游戏很卡,这些卡顿的时间就是STW。

2)、ParNew收集器

        然后就是 ParNew收集器(新生代收集器,并行GC),Parallel Scavenge收集器(新生代收集器,并行GC),Parallel Old收集器(老年代收集器,并行GC),前两个是新生代的收集器,最后一个是老年代的收集器,这组收集器引入了多线程,并发情况下,GC处理效率相比于前一组更高,但是如果在单线程情况下,可能不会比Serial收集器要好,此外,Parallel Scavenge收集器相比于 ParNew收集器只是多了些参数而已。

 3)、CMS收集器

CMS收集器,该收集器设计的初衷是尽量使得STW时间尽量地短, 特点:

  • 初始标记,过程速度很快,只是找到GCRoots,只会引起短暂的STW。
  • 并发标记,虽然速度很慢,但是它可以和业务线程并发执行,不会产生STW。
  • 重新标记,在并发标记过程中,业务代码可能会改变标记的结果,需要进行一次微调,由于是微调,引起的STW很短。
  • 回收内存,也是和业务代码并发。

        前三部分的标记过程就是将可达性分析给拆开了,回收内存主要用于标记-整理,老年代专属。

 4)、G1收集器(唯一一款全区域的垃圾回收器)

        G1收集器,它把内存分为分成了很多的小区域(Region),并且给这些Region做了标记,有些Region放新生代对象,有些Region放老年代对象。

        GC扫描的时候,只扫描一部分Region,不追求一次扫描完,分多次来扫描,这样对业务代码执行影响更小。

        G1收集器可以优化STW的时间小于1ms。本质上CMS与G1都是化整为零的思想。

        最后,做个小总结,垃圾回收本质靠运行时环境,来帮助程序员完成内存释放的工作,但是它有以下缺点:

  • 产生额外的开销。
  • 可能会影响程序的流畅运行(STW造成)

下期见!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/74215.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

溢出的文字省略号显示

溢出的文字省略号显示 1、单行文本溢出显示省略号 源代码 必须满足三个条件:white-space: nowrap; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; nowrap强制一行内显示文本(默认normal自动换行)&#xff0…

vscode跨语言调试

所谓“工欲善其事,必先利其器”,作为一个程序员,调试在项目开发过程中的重要性自然是不言而喻的。 最近项目中遇到的项目是由python和cpp完成的,python端会调用到cpp的库。由于做二次开发需要进行跨语言联调,所以在这…

QList与QVector遍历方法与性能比较

目录 一、 性能测试 二、 QList与QVector耗时对比分析 三、QList遍历方式对比分析 四、QVector遍历方式对比分析 一、 性能测试 最近使用opengl画点云数据时发现比较卡顿,原因是我使用了QList数据结构,后面改为QVector改善很多,速度提升1倍。…

什么是数学思维

什么是数学 数学 [英语:mathematics,源自古希腊语μάθημα(mthēma);经常被缩写为math或maths],是研究数量、结构、变化、空间以及信息等概念的一门学科。 数学 是人类对事物的抽象结构与模式进行严格…

大学生影视主题网页制作 HTML+CSS+JS仿360影视网站 dreamweaver电影HTML网站制作

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置,有div的样式格局,这个实例比较全面,有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

数据结构:排序

目录 插入排序 插入排序 希尔排序 选择排序 选择排序 堆排序 交换排序 冒泡排序 快速排序 递归实现: ●hoare版本 ●三数取中小区间法优化 ●挖坑版本 ●双指针版本 非递归 ●用栈实现 ●用队列实现 归并排序 ● 递归 ●非递归 总结 来了朋友&a…

slot的理解

首先,大概了解一下插槽: 插槽是什么 ![在这里插入图片描述](https://img-blog.csdnimg.cn/90b04660769e49c286ee2e1821d2a2bb.png 插槽:在HTML中 slot 元素 ,作为 Web Components 技术套件的一部分,是Web组件内的一个占…

HashMap1.8也会发生死循环

在网上搜资料时候然后发现网上都说1.7版本的HashMap会发生死链也就是死循环&#xff0c;但是在HashMap中也会产生死循环&#xff0c;接下来直接看代码吧 代码 类名字我忘记改了这是我以前看park时候弄的但是这不重要 当你运行 public class parkAndUnpark {static Map<…

微服务守护神-Sentinel-降级规则

引言 书接上篇 微服务守护神-Sentinel-流控规则 &#xff0c;上面介绍了Sentinel流控规则&#xff0c;本篇继续来Sentinel的降级规则。 降级规则 那啥为降级呢&#xff1f;降级可以理解为下降等次&#xff0c;比如&#xff1a;你从广州到北京&#xff0c;有钱时&#xff0c;…

Kafka的认证

Kafka支持基于SSL和基于SASL的安全认证机制。 基于SSL的认证主要是指Broker和客户端的双路认证。即客户端认证broker的证书&#xff0c;broker也认证客户端的证书。 Kafka还支持通过SASL做客户端认证。SASL是提供认证和数据安全服务的框架。Kafka支持的SASL机制有5种&#xff…

Docker容器化技术入门(一)Docker简介

Docker容器化技术入门&#xff08;一&#xff09;Docker简介前言&#xff08;一&#xff09;Docker简介1 Docker是什么&#xff1f;1.1 Docker的出现1.2 Docker的理念1.3 一句话2 容器与虚拟机比较2.1 容器发展简史2.2 传统虚拟机技术2.3 容器虚拟化技术2.4 对比3 Docker能干什…

华硕编程竞赛11月JAVA专场 D题飞机大战 题解

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

org.eclipse.e4.core.di.InjectionException: Unable to proces

eclipse RCP 项目在eclipse 插件程序中正常运行&#xff0c;导出eclipse product后运行报错。路径&#xff1a;【项目名称】–>workspace–>.metadata–>.log 报错信息如下&#xff1a; !SESSION 2022-12-08 17:19:22.227 ------------------------------------------…

MATLAB、R用改进Fuzzy C-means模糊C均值聚类算法的微博用户特征调研数据聚类研究...

全文链接&#xff1a;http://tecdat.cn/?p30766本文就将采用改进Fuzzy C-means算法对基于用户特征的微博数据进行聚类分析。去年&#xff0c;我们为一位客户进行了短暂的咨询工作&#xff0c;他正在构建一个主要基于微博用户特征聚类研究的分析应用程序&#xff08;点击文末“…

从零开始带你实现一套自己的CI/CD(二)Jenkins+Sonar Qube

目录一、简介二、Sonar环境搭建2.1 下载Docker镜像2.2 使用docker-compose部署三、Sonar Qube基本使用3.1 Maven实现代码检测3.2 Sonar-scanner实现代码检测四、Jenkins集成Sonar Qube4.1 下载插件4.2 SonarQube生成Token4.3 Jenkins配置Sonar Token信息4.4 Jenkins全局工具配置…

word如何设置页码?一分钟教你设置Word文档的页码!

你知道Word怎么设置页码吗&#xff1f;可能你还找不到页码在何处。相信有很多人也会遇到这些类似的问题。如何在Word文档里面的任意一页设置页码呢&#xff1f;word如何设置页码&#xff1f;现在小编就把设置页码的过程和截图分享出来&#xff0c;本文仅供参考使用。有需要的朋…

算法刷题打卡第40天:打家劫舍

打家劫舍 难度&#xff1a;中等 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。…

全解一款六面体结构化网格划分利器-NUMECA IGG

作者 |卢工FunRun 仿真秀优秀讲师 导读&#xff1a;前不久&#xff0c;VIP群有人提问&#xff1a;“老师&#xff0c;NUMECA如何计算带蜗壳叶轮机呢”&#xff1f;笔者使用NUMECA FINE/Turbo&#xff08;以下简称Turbo&#xff09;软件解决叶轮机械气动性能仿真计算已有三年多&…

nRF Connect的使用

一、工具简介 nRF Connect是NORDIC开发的一款低功耗蓝牙测试APP&#xff0c;仅支持安卓。可以扫描和探索低功耗蓝牙设备并与它们通信。 蓝牙通信的核心是向硬件发送数据和接收硬件传回来的数据。 二、准备项 Android手机 蓝牙硬件 三、使用简介 1、进入界面 &#xff08;1&…

某科技公司防火墙配置与管理

目录 杭州继保南瑞电子科技有限公司… 1 公司简介…2需求分析… 错误!未定义书签。公司网络拓扑图…4IP 地址规划 …4设备选型…5技术介绍…6 6.1 DMZ …6 6.2 VPN …6 6.3 NAT …6 6.4 ACL …7项目实施…7 7.1 DMZ 区域配置及结果测试 …7 7.1.1 防火墙基本配置…8 7.1.2 内网…