2023跳槽最新面试题整理——JVM系列

news2024/11/14 20:54:59

      今天是农历2022年腊月二十七了,和往常的春节假期、五一假期和十一假期一样都是团队中坚持到最后的一个。没几天也要快过年了,我先提前向大家拜个早年——祝大家兔年大吉,新春快乐,财源滚滚,万事如意。
      今年从十一假期之后由于种种原因也没有更新文章,今天最后一天,由于做其他的也没有心情,那就老规划——最后一天就自己静下心来整理文章来和大家分享;再加上今年由于YQ放开,大家都在积蓄力量准备明年跳槽,那今天我就开始给大家来持续更新面试题系列吧,这篇文章先来更新JVM系列,打算完整的给大家整理出面试问题重点,然后再看时间是否充裕再来判断是否给大家整理详细问题答案。

1、类加载机制

    1.1、类加载过程

            类加载过程可以初步分成如下几步:
            加载—>验证—>准备—>解析—>初始化
在这里插入图片描述

  • 加载: 根据类的全限定类名从磁盘获取类的二进制字节流。
  • 验证: 字节码验证、文件格式验证、元数据验证和符号引用验证
  • 准备: 静态变量分配内存并且赋予零值
  • 解析: 将在编译阶段的符号引用转化为直接引用,直接指向其内存地址
  • 初始化: 将解析过程中的零值更改为程序员赋值的值

    1.2、类加载器分类

            类加载器分为:启动类加载器、扩展类加载器、应用程序类加载器和自定义类加载器

  • 启动类加载器(Bootstrap Class Loader): 加载< JAVA-HOME >\lib目录下的文件
  • 扩展类加载器(Extension Class Loader): 加载< JAVA-HOME >\lib\ext目录下的文件
  • 应用程序类加载器(Application Class Loader): 加载用户类路径下的所有类包,也就是用户自己写的类
  • 自定义类加载器(User Class Loader): 负责加载用户自定义的类路径下的类包

    1.3、双亲委派机制

            双亲委派机制流程图如下所示:
在这里插入图片描述

             1.3.1、双亲委派如何运行

                   这段我就用大白话来给大家讲解了哈。比如当我自己写的一个类需要加载的时候,它会先去应用程序类加载器中看是否被加载过,发现没有;然后交由应用程序类加载器的父类扩展类加载器看是否被加载过,发现也没有;然后它就会交由扩展类加载器的父类启动类加载器加载,发现同样也没有,上面的这些交由父类加载器就是向上委托;此时会进行向下指派,启动类加载器指派给它的子类扩展类加载器,扩展类加载器指派给应用程序类加载器,此时应用程序类加载器没有向下指派的了,那么就由应用程序类加载器加载。
                   上面如果大家不太明白,你们可以根据我的上段所说的内容去画流程图,那么大家在画流程图之后就完全明白了。

             1.3.2、双亲委派这种机制好处

                   采用双亲委派机制加载主要有一下两点好处:
                   1、保证沙箱安全;比如JDK中的java.lang.String中,如果我对这个类重写了,那么是不生效的,因为它在走到启动类加载器的时候发现已经被加载了,那么就会直接返回,此时就保证了其安全。
                   2、防止重复加载

             1.3.3、为什么在父类加载器没有加载的时候为什么不自己加载,反而交给子类加载器加载?

                   如果直接直接在父类加载器加载,此时加载看着比较省事了,因为不需要再向下指派,但是在下一次需要加载的时候,又需要向上进行查找,那么是比较麻烦的,所以直接进行向下委派给子类加载器加载。

2、JVM运行时数据区

       JVM运行时数据区主要包括堆、虚拟机栈、方法区、本地方法栈和程序计数器。
       运行时数据区图如下所示:
在这里插入图片描述       下面我详细介绍下运行时数据区各个部分其功能:

线程共享:

  • 堆: 主要存放new出来的对象,还有数组和JDK1.8存放字符串常量池;
  • 方法区: 主要存放类信息、方法信息,静态变量和常量池等等;

线程独享:

  • 虚拟机栈: 虚拟机栈是由一个个栈帧组成,当每调用一个方法时就是生成一个栈帧压入虚拟机栈中,栈帧中包含局部变量、操作数栈、动态链接和方法出口;
  • 本地方法栈: 本地方法栈和虚拟机栈的原理一样,只是虚拟机栈调用的是Java方法,但是本地方法栈调用的是本地方法(Native);
  • 程序计数器: 在Java程序运行过程中,会发生线程上下文切换,当线程重新获得CPU时间片时,要保证从上次执行的行数继续执行,那么程序计数器就是保证从原来位置继续执行;

3、JVM对象创建和内存分配机制

       3.1、堆内存结构介绍

              堆内存分为新生代和老年代,新生代:老年代=1:2;新生代中又分为Eden、S0和S1区;Eden:S0:S1=8:1:1;
在这里插入图片描述

       3.2、对象创建流程

              类加载流程如下图所示:
在这里插入图片描述       详细介绍其每一步流程:
              1、加载: 当new对象时,会根据双亲委派机制检查下该类是否被加载过,如果没有加载过则执行类加载过程:加载—>验证—>准备—>解析—>初始化;
              2、分配内存: 当加载完成之后,接下来就要为新生的对象去分配内存空间;当类加载完成之后就知道了对象所需要内存空间;就从堆中找出一块对象所需要内存空间大小的内存给该对象;
                     划分内存方法:
                        1、指针碰撞法: 如果Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点 的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。
                        2、空闲列表法: 如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例, 并更新列表上的记录。
                     解决并发分配内存产生问题:
                     在并发情况下,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。
                     CAS(compare and swap)法:
                     虚拟机采用CAS配上失败重试的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理。
              3、初始化: 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
注意: 这里的初始化和加载过程的初始化是不一样的,加载的初始化是将static修饰的静态变量赋予零值。
              4、设置对象头: 初始化零值之后,要对对象做些必要设置,例如对象属于哪个类的实例对象,GC年龄,对象hashcode和如何找到类的元数据信息等等。
              在虚拟机中,对象在内存中布局分为三部分:对象头、实例数据和对齐填充
              对象头主要包含两部分信息:一部分是运行时自身数据:hash码、GC年龄、偏向锁ID,线程持有的锁等等;另一部分是对象持有类的指针,即对象指向它类元数据的指针,虚拟机通过这个指针找到该对象归属于哪个类
在这里插入图片描述              5、执行init()方法:
                   执行方法,即对象按照程序员的意愿进行初始化。对应到语言层面上讲,就是为属性赋值(注意,这与上面的赋零值不同,这是由程序员赋的值),和执行构造方法。

       3.3、对象内存分配

              对象内存分配流程图如下所示:
在这里插入图片描述
              一般我们认为对象会直接分配到堆中新生代Eden区中,这是不对的,对象可能分配到虚拟机栈中,也有可能分配到堆中的老年代中,这都是可能发生的。下面我来介绍下这几种情况

       3.3.1、对象在栈上分配

              当对象发生了逃逸分析时,那么此时对象就会直接分配到栈中,而不是分配到堆中。这样做的目的是能够减少GC的压力,因为分配到栈中之后,会随着调用这个方法结束而出栈销毁。
              什么是逃逸分析?
                  这个通俗讲就是我在方法内部new一个对象后,该对象只在该方法中使用,不会让方法以外的使用,那么此时就发生了逃逸分析。

       3.3.2、对象在Eden区分配

              正常情况下大量的对象都是分配到堆中新生代的Eden区。

       3.3.3、大对象直接分配至老年代

              当我们创建的是大对象时,会直接分配到老年代中,这样做的的目的减少它在新生代中每次GC来回复制,并且能减少触发minor GC次数而引发的实际不是真正长时间存活的对象而存放老年代所引发的一系列问题。
              大对象是如何判断的呢?
                   在JVM中设置-XX:PretenureSizeThreshold 可以设置大对象的大小

       3.3.4、长期存活的对象进入老年代

               这种也是正常的,当对象创建之后放入堆中新生代的Eden区,然后当新生代满了之后触发minor GC,每次minor GC存活的对象,他们的对象头的GC年龄就会+1,当达到15次之后,就会讲对象存放进老年代,此时就是长期存活对象进入老年代。

       3.3.5、对象动态年龄判断

               当某一年龄的对象占Survivor区的一半以上时,那么他就会将大于等于它的GC年龄直接存放进老年代中。

       3.3.6、老年带空间担保机制

               当触发minor GC的时候都会去看下老年代的可用空间大小,如果老年代的可用空间大小大于等于新生代对象所有之和,那么可以直接触发minor GC;否则会查看是否开启了分配担保机制,如果没有开启,那么会直接触发full GC ,如果开启了,就会看每次minor GC存活的对象平均大小是否小于等于老年代可用空间大小,如果满足,则直接minor GC,否则触发Full GC。
在这里插入图片描述

4、垃圾收集

       4.1、如何判断一个对象是否存活

           判断对象是否存活有两种方式——计数器算法和可达性分析算法

                4.1.1、计数器算法

                   此方法比较简单,每个对象就是专门有个计数的变量,当该对象被引用一次就会+1;引用失效一次就会-1;当计数变量为0时,代表该对象没有被其他对象引用,可以被垃圾回收。
                   该方法有个弊端,就是当两个对象互相引用是,比如A对象引用B对象,B对象又引用A对象,他们之间不可能将计数器减为0,这就无法将对象进行垃圾回收。

                 4.1.2、可达性分析算法

                      将GC roots为起点向下遍历,遍历到的对象说明被其他引用,需要存活,没有遍历到的对象说明被引用,是垃圾对象,会被回收。
                      GC roots根节点可以是静态变量、局部变量等等
在这里插入图片描述

       4.2、垃圾收集算法

               垃圾收集算法主要有复制算法、标记清除算法和标记整理算法

               4.2.1、复制算法

                   效率比较高,主要是年轻代中使用该垃圾算法;它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
               特点: 效率比较高,但是内存利用率不高;每次只能利用50%的内存
在这里插入图片描述

               4.2.2、标记清除算法

               算法分为“标记”和“清除”阶段:标记存活的对象, 统一回收所有未被标记的对象;
                特点: 1、效率比较低(如果需要标记的对象非常多,那么效率就会下降);2、空间利用率较高,但是会产生空间碎片化,导致大对象在存放时不能存放
在这里插入图片描述

               4.2.3、标记整理算法

                根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
在这里插入图片描述

       4.3、垃圾收集器

               常见的垃圾收集器有如下几种:
在这里插入图片描述
               如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

          4.3.1、Serial收集器(-XX:+UseSerialGC -XX:+UseSerialOldGC)

                    Serial(串行) 收集器是最基本、历史最悠久的垃圾收集器了。大家看名字就知道这个收集器是一个单线程收集器了。它 的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束。
在这里插入图片描述
优点:
        它简单而高效(与其他收集器的单线程相比)。Serial 收集器由于没有线程交互的开销,自然可以获得很高的单线程收集效率。
        Serial Old收集器是Serial收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:一种用途是在JDK1.5 以及以前的版本中与Parallel Scavenge收集器搭配使用,另一种用途是作为CMS收集器的后备方案 (当CMS在垃圾收集时,垃圾回收的内存远远不够对象创建所使用的内存,那么此时就会触发Seral Old收集器做兜底,会STW,整个线程不能使用)。

          4.3.2、Parallel收集器(-XX:+UseParallelGC(年轻代),-XX:+UseParallelOldGC(老年代))

                Parallel收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和Serial收集器类似。默认的收集线程数跟cpu核数相同,当然也可以用参数(XX:ParallelGCThreads)指定收集线程数,但是一般不推荐修改。 Parallel Scavenge收集器关注点是吞吐量(高效率的利用CPU)。CMS等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。
                 新生代采用复制算法,老年代采用标记-整理算法。
在这里插入图片描述
                Parallel Old收集器是Parallel Scavenge收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU资源的场合,都可以优先考虑 Parallel Scavenge收集器和Parallel Old收集器(JDK8默认的新生代和老年代收集器)。

          4.3.3、ParNew收集器(-XX:+UseParNewGC)

                ParNew收集器其实跟Parallel收集器很类似,区别主要在于它可以和CMS收集器配合使用。
                新生代采用复制算法,老年代采用标记-整理算法。

          4.3.4、CMS收集器(-XX:+UseConcMarkSweepGC(old))

                CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程 (基本上)同时工作
                从名字中的Mark Sweep这两个词可以看出,CMS收集器是一种 “标记-清除”算法实现。
过程步骤如下:
       1、初始标记: 暂停所有的其他线程(STW),并记录下gc roots直接能引用的对象,速度很快
       2、并发标记: 并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程, 这个过程耗时较长但是不需要停顿用户线程, 可以与垃圾收集线程一起并发运行。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。
       3、重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。主要用到三色标记里的增量更新算法(见下面详解)做重新标记。(也是STW)
       4、并发清理: 开启用户线程,同时GC线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理(见下面三色标记算法详解)。
       5、并发重置: 重置本次GC过程中的标记数据。
在这里插入图片描述

       从它的名字就可以看出它是一款优秀的垃圾收集器,主要优点:并发收集、低停顿。但是它有下面几个明显的缺点:
       1、对CPU资源敏感(会和服务抢资源);
       2、无法处理浮动垃圾(在并发标记和并发清理阶段又产生垃圾,这种浮动垃圾只能等到下一次gc再清理了);
       3、它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生
       4、执行过程中的不确定性,会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况,特别是在并发标记和并发清理阶段会出现,一边回收,系统一边运行,也许没回收完就再次触发full gc,也就是"concurrent mode failure",此时会进入stop the world,用serial old垃圾收集器来回收。

          4.3.5、G1收集器

              G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器。以极高概率满足GC 停顿时间要求的同时,还具备高吞吐量性能特征
在这里插入图片描述              G1将Java堆划分为多个大小相等的独立区域(Region),JVM最多可以有2048个Region。 一般Region大小等于堆大小除以2048,比如堆大小为4096M,则Region大小为2M,当然也可以用参数"XX:G1HeapRegionSize"手动指定Region大小,但是推荐默认的计算方式。
              G1保留了年轻代和老年代的概念,但不再是物理隔阂了,它们都是(可以不连续)Region的集合。
              默认年轻代对堆内存的占比是5%,如果堆大小为4096M,那么年轻代占据200MB左右的内存,对应大概是100个 Region,可以通过“-XX:G1NewSizePercent”设置新生代初始占比,在系统运行中,JVM会不停的给年轻代增加更多 的Region,但是最多新生代的占比不会超过60%,可以通过“-XX:G1MaxNewSizePercent”调整。年轻代中的Eden和 Survivor对应的region也跟之前一样,默认8:1:1,假设年轻代现在有1000个region,eden区对应800个,s0对应100 个,s1对应100个。
              一个Region可能之前是年轻代,如果Region进行了垃圾回收,之后可能又会变成老年代,也就是说Region的区域功能 可能会动态变化
              G1垃圾收集器对于对象什么时候会转移到老年代跟之前讲过的原则一样,唯一不同的是对大对象的处理,G1有专门分配 大对象的Region叫Humongous区,而不是让大对象直接进入老年代的Region中。
              在G1中,大对象的判定规则就是一个大对象超过了一个Region大小的50%,比如按照上面算的,每个Region是2M,只要一个大对象超过了1M,就会被放 入Humongous中,而且一个大对象如果太大,可能会横跨多个Region来存放
              Full GC的时候除了收集年轻代和老年代之外,也会将Humongous区一并回收
G1收集器一次GC的运作过程大致分为以下几个步骤:
       1、初始标记(initial mark,STW): 暂停所有的其他线程,并记录下gc roots直接能引用的对象,速度很快 ;
       2、并发标记(Concurrent Marking): 同CMS的并发标记
       3、最终标记(Remark,STW): 同CMS的重新标记
       4、筛选回收(Cleanup,STW): 筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间(可以用JVM参数 -XX:MaxGCPauseMillis指定)来制定回收计划,比如说老年代此时有1000个 Region都满了,但是因为根据预期停顿时间,本次垃圾回收可能只能停顿200毫秒,那么通过之前回收成本计算得知,可能回收其中800个Region刚好需要200ms,那么就只会回收800个Region(Collection Set,要回收的集合),尽量把GC导致的停顿时间控制在我们指定的范围内。这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。不管是年轻代或是老年代,回收算法主要用的是复制算法,将一个region中的存活对象复制到另一个region中,这种不会像CMS那样 回收完因为有很多内存碎片还需要整理一次,G1采用复制算法回收几乎不会有太多内存碎片。(注意:CMS回收阶段是跟用户线程一起并发执行的,G1因为内部实现太复杂暂时没实现并发回收,不过到了Shenandoah就实现了并发收集,Shenandoah可以看成是G1的升级版本)。
在这里插入图片描述       G1收集器在后台
维护了一个优先列表
,每次根据允许的收集时间,优先选择回收价值最大的Region(这也就是它的名字 Garbage-First的由来),比如一个Region花200ms能回收10M垃圾,另外一个Region花50ms能回收20M垃圾,在回收时间有限情况下,G1当然会优先选择后面这个Region回收。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限时间内可以尽可能高的收集效率
       G1垃圾收集分类:
              1、YoungGC:
                  YoungGC并不是说现有的Eden区放满了就会马上触发,G1会计算下现在Eden区回收大概要多久时间,如果回收时间远远小于参数 -XX:MaxGCPauseMills 设定的值,那么增加年轻代的region,继续给新对象存放,不会马上做Young GC,直到下一次Eden区放满,G1计算回收时间接近参数 -XX:MaxGCPauseMills 设定的值,那么就会触发Young GC。
              2、MixedGC:
                  不是FullGC,老年代的堆占有率达到参数(-XX:InitiatingHeapOccupancyPercent)设定的值则触发,回收所有的Young和部分Old(根据期望的GC停顿时间确定old区垃圾收集的优先顺序)以及大对象区,正常情况G1的垃圾收集是先做MixedGC,主要使用复制算法,需要把各个region中存活的对象拷贝到别的region里去,拷贝过程中如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC。
              3、Full GC:
                  停止系统程序,然后采用单线程进行标记、清理和压缩整理,好空闲出来一批Region来供下一次MixedGC使用,这 个过程是非常耗时的。(Shenandoah优化成多线程收集了)

       4.4、垃圾收集底层算法

           4.4.1、三色标记

               在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。
               这里我们引入“三色标记”来给大家解释下,把Gc roots可达性分析遍历对象过程中遇到的对象, 按照“是否访问过”这个条件标记成以下三种颜色:

  • 黑色: 表示对象已经被垃圾收集器访问过, 且这个对象的所有引用都已经扫描过黑色的对象代表已经扫描过, 它是安全存活的, 如果有其他对象引用指向了黑色对象,无须重新扫描一遍。 黑色对象不可能直接(不经过灰色对象) 指向某个白色对象。
  • 灰色: 表示对象已经被垃圾收集器访问过, 但这个对象上至少存在一个引用还没有被扫描过
  • 白色: 表示对象尚未被垃圾收集器访问过。 显然在可达性分析刚刚开始的阶段, 所有的对象都是白色的, 若 在分析结束的阶段, 仍然是白色的对象, 即代表不可达
    在这里插入图片描述

       4.5、一次完整GC流程

              这里准备用大白话来给大家来讲解哈。首先对象创建之后,会存放进堆中新生代的Eden区中,当Eden区满了,会触发minoe GC,存活的对象移动到S0区,并且存活的对象GC年龄+1;此时又有新建的对象存放进Eden区,当Eden区满了,就又会触发minior GC,这次不单单回收Eden区,还会回收S区,此时存活的对象会移动到S1区,存活的对象年龄+1;反反复复这样垃圾回收,当对象GC年龄大于15次时,那么此时对象会存放进老年代;当老年代满了之后,会触发Full GC,Full GC不单单回收老年代,它还回收新生代,Full GC 的时间会比较长,大概是Minor GC的十倍左右。
              好了,上面就是一次完整的GC流程,大白话讲解的应该还算比较清晰。不理解的可以在评论中评论哦。

5、JVM调优

              这个JVM调优就先不给大家讲解了吧,因为今天是年前上班的最后一天,已经下班了,我还明天中午的高铁,今天晚上回去还要收拾东西;今天就不讲解了,等有时间了给大家补上哈
              废话少说,赶紧来个结尾,准备收拾东西下班回家过年!
              再次提前祝大家新年快乐哦(从下写作文老师就教导我们写作文要首尾相应🐶)
              文章中有讲解不对的内容希望大家在评论区中指出哦,希望大家点赞评论转发哦,点赞超过三个我就更新下一篇——MySQL系列

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

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

相关文章

如何使用 Selenium 实现自动化操作?

目录 前言 一、关于Selenium 1.1、为什么选择它作为web自动化的测试工具&#xff1f; 1.2、Selenium操作浏览器的原理 二、实现一个简单的自动化 2.1、使用自动化操作浏览器 2.2、Selenium常用的API 2.2.1、查找页面元素 小结 前言 本篇咱们来谈谈Selenium自动化脚本是…

pfx证书转pem、crt、key

今天测试端的服务器突然不能下载苹果APP了&#xff0c;经查看&#xff0c;发现原来是测试环境的https证书过期了&#xff0c;需要更换证书&#xff0c;于是赶紧从阿里云更新我们的最新证书 我们程序部署在tomcat上&#xff0c;于是下载tomcat版本&#xff0c;下载完成后如下 我…

【微信小程序-原生开发】实用教程05-首页(含自定义调试模式、插入图片、图文排版、底部留白、添加本地图片)

开始前&#xff0c;请先完成启动/欢迎/首屏广告页的开发&#xff0c;详见 【微信小程序-原生开发】实用教程04-启动/欢迎/首屏广告页&#xff08;含倒计时、添加文字、rpx、定义变量和函数、读取变量、修改变量、wx.reLaunch 页面跳转、生命周期 onReady等) https://blog.csdn…

输入设备应用

1.输入设备其实就是能够产生输入事件的设备就称为输入设备&#xff0c; 常见的输入设备包括鼠标、键盘、触摸屏、按钮等等&#xff0c;它们都能够产生输入事件&#xff0c;产生输入数据给计算机系统。2.对于输入设备的应用编程其主要是获取输入设备上报的数据、 输入设备当前状…

驱动程序那点事儿

是什么 驱动程序是一个软件组件&#xff0c;&#xff08;添加到操作系统中的一小块代码&#xff09;&#xff0c;是操作系统和设备通信的桥梁。应用程序需要从设备中读取某些数据&#xff0c;操作系统会调用由驱动程序实现的函数。驱动程序了解如何与设备硬件通信以获取数据。当…

菜鸟程序员如何快速进阶成为编程老司机?

菜鸟程序员如何摆脱稚嫩&#xff0c;快速成长为一名资深码农&#xff1f; 以下这些事情&#xff0c;帮你快速打好基础。 如果你想成为更好的开发者&#xff0c;你应该尤其注意第10点和第14点。 1.积极大胆地谷歌。你得知道如何有效地组织搜索关键字&#xff0c;查阅别人写的…

高并发系统设计 --热点key问题解决

热点Key问题&#xff0c;这是一个老生常谈的问题了&#xff0c;今天我们来仔细的去剖析这个问题。 热点key带来的问题 流量集中。达到服务器处理上限&#xff08;CPU&#xff0c;网络IO等&#xff09;会影响在同一个Redis实例上其他key的读写请求操作热key请求落到同一个Redi…

【魅力开源】第7集:开源ERP系统Odoo发展史(Odoo中文社区野史2019版)

文章目录前言历程后记前言 开源 ERP 系统 Odoo 的发展史。 历程 2002 年比利时13 岁开 始学习编程序的 Fabien Pinckaers 所创建创办了Tiny Sprl 公司。Tiny Sprl 公司的第一个产品就是开发 Tiny ERP&#xff0c;即后来的 OpenERP&#xff0c;现在改名为Odoo。 2007 年 Ope…

Sklearn标准化和归一化方法汇总(3):范数归一化

Sklearn中与特征缩放有关的五个函数和类&#xff0c;全部位于sklearn.preprocessing包内。作为一个系列文章&#xff0c;我们将逐一讲解Sklearn中提供的标准化和归一化方法&#xff0c;以下是本系列已发布的文章列表&#xff1a; Sklearn标准化和归一化方法汇总(1)&#xff1a…

博云荣获证券基金信创联盟年度优秀成员

1月12日&#xff0c;证券基金行业信息技术应用创新联盟&#xff08;以下简称“联盟”&#xff09;2022年度峰会在上海顺利举行。会上&#xff0c;联盟为2022年积极参与联盟工作的成员单位进行了颁奖&#xff0c;博云获评信创联盟年度优秀成员奖。 联盟是在中国证券监督管理委员…

Spring | SM整合(Spring+MyBatis)

0️⃣使用工具编辑器&#xff1a;IDEA企业版构建系统&#xff1a;Maven数据库&#xff1a;MySQL1️⃣创建项目&#x1f38f;创建maven项目选择新建项目&#xff0c;在E盘下创建名为SMDemo的项目&#xff0c;构建系统选择Maven.&#x1f38f;项目结构src/main/java - java 逻辑代…

企业宣传新闻稿撰写方法和技巧分享,纯干货

企业宣传新闻稿重点在于“宣传”&#xff0c;目的性强&#xff0c;具有极强的商业价值&#xff0c;怎么撰写是一大难关。 企业新闻稿堪比公关小组&#xff0c;表面上看起来只是简简单单一篇新闻稿&#xff0c;但是实际上企业新闻稿也能起到大作用&#xff0c;企业新闻稿的价值…

Python Kafka客户端性能测试比较

前言 由于工作原因使用到了 Kafka&#xff0c;而现有的代码并不能满足性能需求&#xff0c;所以需要开发高效读写 Kafka 的工具&#xff0c;本文是一个 Python Kafka Client 的性能测试记录&#xff0c;通过本次测试&#xff0c;可以知道选用什么第三方库的性能最高&#xff0c…

umi4+antd5兼容360安全浏览器

项目场景&#xff1a; umi4创建的大屏项目&#xff0c;部分模块使用了antd5进行开发 问题描述 开发完成后&#xff0c;得知客户是360安全浏览器&#xff0c;内核为86&#xff0c;测试过程中出现了样式混乱。 混乱样式有下拉内容的组件&#xff08;如select、dataPicker&#…

Microsoft 365中的智能应用—翻译、朗读、听写

Microsoft 365 是一种订阅式的跨平台办公软件&#xff0c;基于云平台提供多种服务&#xff0c;通过将Word、Excel、PowerPoint和Outlook、OneNote等应用与OneDrive 和 Microsoft Teams等强大的云服务相结合&#xff0c;让任何人使用任何设备随时随地创建和共享内容。 Microsof…

【JavaScript】仿青柠搜索界面

点击搜索栏&#xff0c;背景模糊&#xff0c;出现图标。点击界面任意处&#xff0c;失去焦点&#xff0c;恢复原样 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X…

Elasticsearch高级查询—— 查询所有文档

目录一、初始化文档数据二、查询所有文档示例一、初始化文档数据 在 Postman 中&#xff0c;向 ES 服务器发 POST 请求 &#xff1a;http://localhost:9200/user/_doc/1&#xff0c;请求体内容为&#xff1a; {"name":"张三","age":22,"sex…

Qt的开源库TabToolbar

开源地址&#xff1a;https://github.com/SeriousAlexej/TabToolbar 该库的使用方式有两种&#xff1a; 使用json配置文件配置TabToolBar使用代码构建TabToolBar 编译 项目是使用Qt和CMake管理的&#xff0c;并且在开发的时候使用的是Qt6&#xff0c;我实测通过更改CMake的…

设计模式——代理模式

文章目录引入案例提出问题解决思路遇到的困难代理模式概念生活中的代理相关术语静态代理动态代理织入的概念基于JDK的动态代理基于Cglib的动态代理JDK 和 CGLIB 的区别引入案例 计数器的接口 public interface Calculator {int add(int i, int j);int sub(int i, int j);int …

pandas案例——预处理部分地区数据

数据清洗的任务是过滤那些不符合要求的数据&#xff0c;将过滤的结果交给业务主管部门&#xff0c;确认是否过滤掉还是由业务单位修正之后再进行抽取。不符合要求的数据主要是有不完整的数据、错误的数据、重复的数据三大类。数据清洗是与问卷审核不同&#xff0c;录入后的数据…