面试准备知识点与总结——(虚拟机篇)

news2024/9/24 5:30:29

目录

    • JVM的内存结构
    • JVM哪些部分会发生内存溢出
    • 方法区、永久代、元空间三者之间的关系
    • JVM内存参数
    • JVM垃圾回收算法
      • 1.标记清除法
      • 2.标记整理
      • 3.标记复制
    • 说说GC和分代回收算法
    • 三色标记与并发漏标的问题
    • 垃圾回收器
    • 项目中什么时候会内存溢出,怎么解决
    • 类加载过程三个阶段
    • 何为双亲委派
    • 对象的引用类型分为哪几类?
    • 谈谈finalize的理解

JVM的内存结构

Java Source 和 Java Class 分别是java的源代码 和 编译之后的字节码文件

在这里插入图片描述

  • 执行 javac 命令编译源代码为字节码
  • 执行 java 命令
    1. 创建 JVM,调用类加载子系统加载 class,将类的信息存入方法区
    2. 创建 main 线程,使用的内存区域是 JVM 虚拟机栈,开始执行 main 方法代码
    3. 如果遇到了未见过的类,会继续触发类加载过程,同样会存入方法区
    4. 需要创建对象,会使用内存来存储对象
    5. 不再使用的对象,会由垃圾回收器在内存不足时回收其内存
    6. 调用方法时,方法内的局部变量、方法参数所使用的是 JVM 虚拟机栈中的栈中内存
    7. 调用方法时,先要到方法区获得到该方法的字节码指令,由解释器将字节码指令解释为机器码执行
    8. 调用方法时,会将要执行的指令行号读到程序计数器,这样当发生了线程切换,恢复时就可以从中断的位置继续
    9. 对于非 java 实现的方法调用,使用内存称为本地方法栈
    10. 对于热点方法调用,或者频繁的循环代码,由 JIT 即时编译器将这些代码编译成机器码缓存,提高执行性能

说明: 加粗字体代表了 JVM 虚拟机组件

对于 Oracle 的 Hotspot 虚拟机实现,不区分虚拟机栈和本地方法栈

线程私有:

  • 程序计数器
  • 虚拟机栈

线程共享:

  • 方法区

JVM哪些部分会发生内存溢出

不会出现内存溢出的区域 – 程序计数器

除了程序计数器不会出现内存溢出,其他部分都有可能出现内存溢出

一. OutOfMemoryError 的情况

  • 堆内存耗尽 –——对象越来越多,又一直在使用,不能被垃圾回收
  • 方法区内存耗尽 –—— 加载的类越来越多,很多框架都会在运行期间动态产生新的类
  • 虚拟机栈累积 –—— 每个线程最多会占用 1 M 内存,线程个数越来越多,而又长时间运行不销毁时

二. 出现 StackOverflowError 的区域

  • JVM 虚拟机栈,原因有方法递归调用未正确结束、反序列化 json 时循环引用

方法区、永久代、元空间三者之间的关系

  • 方法区是 JVM 规范中定义的一块内存区域,用来存储类元数据、方法字节码、即时编译器需要的信息等
  • 永久代是 Hotspot 虚拟机对 JVM 规范的实现(1.8 之前)
  • 元空间是 Hotspot 虚拟机对 JVM 规范的另一种实现(1.8 以后),使用本地内存作为这些信息的存储空间

下面是元空间的解析说明

在这里插入图片描述

从上图的类加载流程,及元空间何时加载数据可以看出

  • 当第一次用到某个类是,由类加载器将 class 文件的类元信息读入,并存储于元空间
  • X,Y 的类元信息是存储于元空间中,无法直接访问
  • 可以用 X.class,Y.class 间接访问类元信息,它们俩属于 java 对象,我们的代码中可以使用

下面是回收数据的流程

在这里插入图片描述

从这张图可以看到

  • 堆内存中:当一个类加载器对象,这个类加载器对象加载的所有类对象,这些类对象对应的所有实例对象都没人引用时,GC 时就会对它们占用的对内存进行释放
  • 元空间中:内存释放以类加载器为单位当堆中类加载器内存释放时,对应的元空间中的类元信息也会释放

JVM内存参数

  • -Xms 最小堆内存(包括新生代和老年代)
  • -Xmx 最大对内存(包括新生代和老年代)
  • 通常建议将 -Xms 与 -Xmx 设置为大小相等,即不需要保留内存,不需要从小到大增长,这样性能较好
  • -XX:NewSize 与 -XX:MaxNewSize 设置新生代的最小与最大值,但一般不建议设置,由 JVM 自己控制
  • -Xmn 设置新生代大小,相当于同时设置了 -XX:NewSize 与 -XX:MaxNewSize 并且取值相等
  • 保留是指,一开始不会占用那么多内存,随着使用内存越来越多,会逐步使用这部分保留内存。下同

在这里插入图片描述


在这里插入图片描述

对于下面这题,来练习一下上面提到的参数

在这里插入图片描述

答案:最小内存值为10G,Survivor区总大小是2G——2048m


JVM垃圾回收算法

1.标记清除法

  1. 找到 GC Root 对象,即那些一定不会被回收的对象,如正执行方法内局部变量引用的对象、静态变量引用的对象
  2. 标记阶段:沿着 GC Root 对象的引用链找,直接或间接引用到的对象加上标记
  3. 清除阶段:释放未加标记的对象占用的内存

在这里插入图片描述


特点:

  • 标记速度与存活对象线性关系
  • 清除速度与内存大小线性关系
  • 缺点是会产生内存碎片

2.标记整理

  1. 和前面的标记阶段、清理阶段与标记清除法类似
  2. 只是多了一步整理的动作,将存活对象向一端移动,可以避免内存碎片产生

在这里插入图片描述

特点:

  • 标记速度与存活对象线性关系

  • 清除与整理速度与内存大小成线性关系

  • 缺点是性能上较慢

适合垃圾少的,不用多次移动,适合老年代


3.标记复制

在这里插入图片描述

  1. 将整个内存分成两个大小相等的区域,from 和 to,其中 to 总是处于空闲,from 存储新创建的对象
  2. 标记阶段与前面的算法类似
  3. 在找出存活对象后,会将它们从 from 复制到 to 区域,复制的过程中自然完成了碎片整理
  4. 复制完成后,交换 from 和 to 的位置即可

特点:

  • 标记与复制速度与存活对象成线性关系
  • 缺点是会占用成倍的空间,毕竟是以空间换时间

但是它不适合老年代的垃圾回收,老年代是存活对象比较多,垃圾对象比较少,这样每次垃圾回手都会进行很多次从form复制到to,也影响了性能

From和To就是Survivor区中的一块


总结标记整理算法适合老年代的垃圾回收,标记复制算法适合新生代的垃圾回收


说说GC和分代回收算法

GC 的目的在于实现无用对象内存自动释放,减少内存碎片、加快分配速度

GC 要点:

  • 回收区域是堆内存,不包括虚拟机栈
  • 判断无用对象,使用可达性分析算法(以一定不会回收的对象为根,沿着根对象找,找到了的对象加上标记),三色标记法标记存活对象,回收未标记对象
  • GC 具体的实现称为垃圾回收器
  • GC 大都采用了分代回收思想
    • 理论依据是大部分对象朝生夕灭,用完立刻就可以回收,另有少部分对象会长时间存活,每次很难回收
    • 根据这两类对象的特性将回收区域分为新生代老年代,新生代采用标记复制法、老年代一般采用标记整理法
  • 根据 GC 的规模可以分成 Minor GCMixed GCFull GC

分代回收

下面是B站上黑马满一航老师的分代回收的分析流程,超级详细,看一遍就懂。

经过下面的分代回收的流程,会对这些新生代,伊甸园等名字有了新的理解,也会感概起名的人实在是太优雅了

1.伊甸园 eden,最初对象都分配到这里,与幸存区 survivor(分成 from 和 to)合称新生代。
在这里插入图片描述


2.当伊甸园内存不足,标记伊甸园与 from(现阶段没有)的存活对象
在这里插入图片描述


3.将存活对象采用复制算法复制到 to 中,复制完毕后,伊甸园和 from 内存都得到释放

在这里插入图片描述


4.将 from 和 to 交换位置
在这里插入图片描述


5.经过一段时间后伊甸园的内存又出现不足
在这里插入图片描述


6.标记伊甸园与 from(现阶段没有)的存活对象

在这里插入图片描述


7.将存活对象采用复制算法复制到 to 中

在这里插入图片描述


8.复制完毕后,伊甸园和 from 内存都得到释放

在这里插入图片描述


9.将 from 和 to 交换位置
在这里插入图片描述
10.老年代 old,当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或大对象(免得拷贝来拷贝去,浪费更多时间)会导致提前晋升)


GC 规模

  • Minor GC 发生在新生代的垃圾回收,暂停时间短

  • Mixed GC 新生代 + 老年代部分区域的垃圾回收,G1 收集器特有

  • Full GC 新生代 + 老年代完整垃圾回收,暂停时间长,应尽力避免


三色标记与并发漏标的问题

前面对从根对象找到的对象添加标记,这个添加标记的动作不是一次完成的,而是需要一个过程的

用三种颜色记录对象的标记状态

  • 黑色 – 已标记(表示沿着根对象引用已经找到了该对象了,而且该对象内部的其他引用也处理完毕了)
  • 灰色 – 标记中(表示沿着根对象引用已经找到了该对象了,但该对象内部的其他引用还未被处理完成,正在处理中)
  • 白色 – 还未标记(表示未被处理的)

并发漏标问题

比较先进的垃圾回收器都支持并发标记,即在标记过程中,用户线程仍然能工作。但这样带来一个新的问题,如果用户线程修改了对象引用,那么就存在漏标问题。

场景如下图

1.如图所示标记工作尚未完成

在这里插入图片描述

2.用户线程同时在工作,断开了第一层 3、4 两个对象之间的引用,这时对于正在处理 3 号对象的垃圾回收线程来讲,它会将 4 号对象当做是白色垃圾

在这里插入图片描述

3.但如果其他用户线程又建立了 2、4 两个对象的引用,这时因为 2 号对象是黑色已处理对象了,因此垃圾回收线程不会察觉到这个引用关系的变化,从而产生了漏标

在这里插入图片描述

4.如果用户线程让黑色对象引用了一个新增对象,一样会存在漏标问题

在这里插入图片描述


因此对于并发标记而言,必须解决漏标问题,也就是要记录标记过程中的变化。
有两种解决方法:

  1. Incremental Update 增量更新法CMS 垃圾回收器采用

    • 思路是拦截每次赋值动作,只要赋值发生,被赋值的对象就会被记录下来(也就是标为黑色的那个),等所有标记操作做完了,必须stop the world(STW)让线程停止,对标记过程中记录的对象再做一遍处理,在重新标记阶段再确认一遍
  2. Snapshot At The Beginning,SATB 原始快照法G1 垃圾回收器采用

    • 思路也是拦截每次赋值动作,不过记录的对象不同,也需要在重新标记阶段对这些对象二次处理
    • 新加对象会被记录
    • 被删除引用关系的对象(也就是白色的那个对象)也被记录

垃圾回收器

垃圾回收器 - Parallel GC(并行GC)

  • eden 内存不足发生 Minor GC,采用标记复制算法,需要暂停用户线程

  • old 内存不足发生 Full GC,采用标记整理算法,需要暂停用户线程

  • 注重吞吐量

并行GC名字由来,虽然在新生代和老年代都会调用STW,但是暂停时间,会使用多个线程并行完成垃圾回收。虽然有暂停,但并行回收,停止时间较短


垃圾回收器 - ConcurrentMarkSweep GC

  • 它是工作在 old 老年代,支持并发标记的一款回收器,采用并发清除算法,它是用增量更新法来解决并发标记时的多标漏标问题的

    • 并发标记时不需暂停用户线程
    • 重新标记时仍需暂停用户线程
  • 如果并发失败(即回收速度赶不上创建新对象速度),会触发 Failback Full GC (保底策略)

  • 注重响应时间


垃圾回收器 - G1 GC

  • 响应时间与吞吐量兼顾
  • 划分成多个区域,每个区域都可以充当 eden,survivor,old, humongous,其中 humongous 专为大对象准备,因为大对象的复制成本高
  • 分成三个阶段:新生代回收(伊甸园内存不足,标记复制并STW)、并发标记(老年代并发标记,重新标记需STW,对漏标问题采用原始快照法)、混合收集
  • 如果并发失败(即回收速度赶不上创建新对象速度),会触发 Full GC

G1回收阶段 - 并发标记与混合收集流程,下图仍然是黑马满一航老师的图解分析,简明易懂

注:S是幸存区(Survivor),E是伊甸园区(eden),O是老年代(Old)

①当老年代占用内存超过阈值后,触发并发标记,这时无需暂停用户线程
在这里插入图片描述

②并发标记之后,会有重新标记阶段解决漏标问题,此时需要暂停用户线程。这些都完成后就知道了老年代有哪些存活对象,随后进入混合收集阶段。此时不会对所有老年代区域进行回收,而是根据暂停时间目标优先回收价值高(存活对象少)的区域(这也是 Gabage First 名称的由来)也就是下图标红的O。
在这里插入图片描述

③ 混合收集阶段中,参与复制的有 eden、survivor、old,下图显示了伊甸园和幸存区的存活对象复制
在这里插入图片描述

④下图显示了老年代和幸存区晋升的存活对象的复制

在这里插入图片描述

⑤复制完成,内存得到释放。进入下一轮的新生代回收、并发标记、混合收集

在这里插入图片描述


项目中什么时候会内存溢出,怎么解决

① 误用线程池导致的内存溢出

误用固定大小的线程池

在这里插入图片描述


误用带缓冲线程池

在这里插入图片描述

所以总结一下,不要用executors工具类中默认的线程池,很容易把握不住;防止策略,自己去使用它的构造方法,根据情况设置有大小限制


② 查询数据量太大导致的内存溢出
在项目上线后,比如一千万条的商品信息,如果编码中存在findAll()方法,会消耗大量内存,如果是多个用户都访问,调用了findAll(),用不了多久服务器内存就被耗尽
除了编码中不使用findAll()方法,还要注意,使用findAll()后面跟条件查询时,有时候条件可能会失效,所以后面一定要跟一个limit,限制查询条目数


③ 动态生成类导致的内存溢出
在这里插入图片描述


类加载过程三个阶段

①. 加载

  1. 将类的字节码载入方法区,并创建类.class 对象

  2. 如果此类的父类没有加载,先加载父类

  3. 加载是懒惰执行


②. 链接

  1. 验证 – 验证类是否符合 Class 规范,合法性、安全性检查
  2. 准备 – 为 static 变量分配空间,设置默认值
  3. 解析 – 将常量池的符号引用(内部类类名)解析为直接引用(类的地址);并非初始化完成后,所有就停止了,解析步骤不是一步到位的而是一点点完成的

③. 初始化

  1. 静态代码块、static 修饰的变量赋值、static final 修饰的引用类型变量赋值,会被合并成一个 <cinit> 方法,在初始化时被调用
  2. static final 修饰的基本类型变量赋值,在链接阶段就已完成
  3. 初始化是懒惰执行

访问static final 修饰的基本类型变量,不会导致类的加载和初始化,若是访问static final 修饰的引用类型变量既会导致类的加载也会导致类的初始化


何为双亲委派

jdk 8 的类加载器

名称加载哪的类说明
Bootstrap ClassLoaderJAVA_HOME/jre/lib无法直接访问
Extension ClassLoaderJAVA_HOME/jre/lib/ext上级为 Bootstrap,显示为 null
Application ClassLoaderclasspath上级为 Extension
自定义类加载器自定义上级为 Application

Bootstrap ClassLoader 启动加载器, Extension ClassLoader 扩展加载器,Application ClassLoader 应用程序加载器

双亲委派机制
所谓的双亲委派,就是指优先委派上级类加载器进行加载,如果上级类加载器

  • 能找到这个类(如String.class),由上级加载,加载后该类也对下级加载器可见,共享了
  • 找不到这个类(如自己写的Student.class),则下放下级类加载器执行加载,下级加载器加载后该类对上级加载器不可见

双亲委派的目的有两点

  1. 让上级类加载器中的类对下级共享(反之不行),即能让你的类能依赖到 jdk 提供的核心类

  2. 让类的加载有优先次序,保证核心类优先加载


自己编写类加载器就能加载一个假冒的 java.lang.System 吗? 答案是不行

  • 假设你自己的类加载器用双亲委派,那么优先由启动类加载器加载真正的 java.lang.System,自然不会加载假冒的

  • 假设你自己的类加载器不用双亲委派,那么你的类加载器加载假冒的 java.lang.System 时,它需要先加载父类 java.lang.Object,而你没有用委派,找不到 java.lang.Object 所以加载会失败

  • 以上也仅仅是假设。事实上操作你就会发现,自定义类加载器加载以 java. 打头的类时,会抛安全异常,在 jdk9 以上版本这些特殊包名都与模块进行了绑定,更连编译都过不了


对象的引用类型分为哪几类?

强引用

  1. 普通变量赋值即为强引用,如 A a = new A();

  2. 通过 GC Root 的引用链,如果强引用不到该对象,该对象才能被回收

在这里插入图片描述


软引用(SoftReference)

  1. 例如:SoftReference a = new SoftReference(new A());

  2. 如果仅有软引用该对象时,首次垃圾回收不会回收该对象如果内存仍不足,再次回收时才会释放对象

  3. 软引用自身需要配合引用队列来释放

  4. 典型例子是反射数据

在这里插入图片描述


弱引用(WeakReference)

  1. 例如:WeakReference a = new WeakReference(new A());

  2. 如果仅有弱引用引用该对象时,只要发生垃圾回收,就会释放该对象

  3. 弱引用自身需要配合引用队列来释放

  4. 典型例子是 ThreadLocalMap 中的 Entry 对象

在这里插入图片描述


虚引用(PhantomReference)

  1. 例如: PhantomReference a = new PhantomReference(new A(), referenceQueue);

  2. 必须配合引用队列一起使用,当虚引用所引用的对象被回收时,由 Reference Handler 线程将虚引用对象入队,这样就可以知道哪些对象被回收,从而对它们关联的资源做进一步处理

  3. 典型例子是 Cleaner 释放 DirectByteBuffer 关联的直接内存

在这里插入图片描述

解释含义:当a,b对象被释放后,把它们的虚引用放入引用队列中先记住哪些对象被回收了,当它们的java中占用内存释放完,通过引用队列找到引用a,b;再将其关联的外部资源也释放掉

简单点说:你在一家公司工作,公司为了开源节流把你裁了(对象被回收),这是后勤管理人员就会把被开的人记录在一个名单上(放入引用队列),当你被开除后,把你使用的工位,电脑给还原恢复(释放外部资源)


弱,虚引用配合引用对列,目的是找到哪些java对象被回收(比如ThreadLocalMap 中的 Entry 对象的key是弱引用,会被回收掉),从而进行对它们关联的资源(key关联的value强引用)进行进一步清理,从java9开始引入了Cleaner对象


谈谈finalize的理解

finalize

  • 它是 Object 中的一个方法,如果子类重写它,垃圾回收时此方法会被调用,可以在其中进行资源释放和清理工作
  • 将资源释放和清理放在 finalize 方法中非常不好,非常影响性能,严重时甚至会引起 OOM,从 Java9 开始就被标注为 @Deprecated,不建议被使用了

finalize 缺点

两个非常不好的点

①无法保证资源释放:FinalizerThread 是守护线程,代码很有可能没来得及执行完,线程就结束了

在这里插入图片描述


②无法判断是否发生错误:执行 finalize 方法时,会吞掉任意异常(Throwable)

在这里插入图片描述


finalize 原理

  1. 对 finalize 方法进行处理的核心逻辑位于 java.lang.ref.Finalizer 类中,它包含了名为 unfinalized 的静态变量(双向链表结构),Finalizer 也可被视为另一种引用对象(地位与软、弱、虚相当,只是不对外,无法直接使用)

  2. 当重写了 finalize 方法的对象,在构造方法调用之时,JVM 都会将其包装成一个 Finalizer 对象,并加入 unfinalized 链表中
    在这里插入图片描述

  3. Finalizer 类中还有另一个重要的静态变量,即 ReferenceQueue 引用队列,刚开始它是空的。当狗对象可以被当作垃圾回收时,就会把这些狗对象对应的 Finalizer 对象加入此引用队列

  4. 但此时 Dog 对象还没法被立刻回收,因为 unfinalized -> Finalizer 这一引用链还在引用它嘛,为的是【先别着急回收啊,等我调完 finalize 方法,再回收】

  5. FinalizerThread 线程会从 ReferenceQueue 中逐一取出每个 Finalizer 对象,把它们从链表断开并真正调用 finallize 方法
    在这里插入图片描述

  6. 由于整个 Finalizer 对象已经从 unfinalized 链表中断开,这样没谁能引用到它和狗对象,所以下次 gc 时就被回收了


影响性能上

内存释放不及时:重写了 finalize 方法的对象在第一次被 gc 时,并不能及时释放它占用的内存,因为要等着 FinalizerThread 调用完 finalize,把它从 unfinalized 队列移除后,第二次 gc 时才能真正释放内存
回收时速度慢:gc本就时因为内存不足引起才执行,finalize调用又很慢(两个队列的移除操作,都是加锁串行执行的,用来释放连接类的资源也不快),不能及时释放内存,对象释放不及时就会逐步晋升到老年代,老年代垃圾积累过多又会引发full gc, full gc后释放速度如果仍然跟不上创建新对象速度就会OOM(内存溢出)


质疑对比

  • 有的文章提到【Finalizer 线程会和我们的主线程进行竞争,不过由于它的优先级较低,获取到的CPU时间较少,因此它永远也赶不上主线程的步伐】这个显然是错误的,FinalizerThread 的优先级较普通线程更高(最大优先级 - 2),原因应该是 finalize 串行执行慢等原因综合导致

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

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

相关文章

Docker 架构简介

Docker 架构 Docker 包括三个基本概念: 镜像&#xff08;Image&#xff09;&#xff1a;Docker 镜像&#xff08;Image&#xff09;&#xff0c;就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。容器&am…

【力扣-LeetCode】64. 最小路径和 C++题解

64. 最小路径和难度中等1430收藏分享切换为英文接收动态反馈给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。说明&#xff1a;每次只能向下或者向右移动一步。示例 1&#xff1a;输入&#xff…

实例1:控制树莓派板载LED灯闪烁

实例1&#xff1a;控制树莓派板载LED灯闪烁 实验目的 通过背景知识学习&#xff0c;了解四足机器人mini pupper搭载的微型控制计算机&#xff1a;树莓派。通过对树莓派板载LED灯的状态读写控制&#xff0c;熟悉树莓派本身的操作及Linux中文件的读写。掌握常见函数time.sleep(…

初识Hadoop,走进大数据世界

文章目录数据&#xff01;数据&#xff01;遇到的问题Hadoop的出现相较于其他系统的优势关系型数据库网格计算本文章属于Hadoop系列文章&#xff0c;分享Hadoop相关知识。后续文章中会继续分享Hadoop的组件、MapReduce、HDFS、Hbase、Flume、Pig、Spark、Hadoop集群管理系统以及…

rewrite中的if、break、last

目录 rewrite 作用&#xff1a; 依赖&#xff1a; 打开重定向日志&#xff1a; if 判断&#xff1a; location {} 本身有反复匹配执行特征 在 location 中加入 break 和 last &#xff08;不一样&#xff09; 加了break后&#xff0c;立刻停止向下 且 跳出。 加了last&#xf…

Windows 版本ffmpeg编译概述

在使用ffmpeg过程当中&#xff0c;ffmpeg在Linux(包括mac,android)编译非常容易,直接configure,make即可&#xff0c;Android需要交叉编译,在windows就比较麻烦&#xff0c;庆幸的是ffmpeg官方提供已编译好Windows版本的二进制库&#xff08;http://ffmpeg.org/download.html#b…

使用vector<char>作为输入缓冲区

一、引言 当我们编写代码&#xff1a;实现网络接收、读取文件内容等功能时&#xff0c;我们往往要在内存中开辟一个输入缓冲区(又名&#xff1a;input buffer/读缓冲区&#xff09;来存贮接收到的数据。在C里面我们可以用如下方法开辟输入缓冲区。 ①使用C语言中的数组&#x…

【Spring教程】1.Spring概述

1、概述 1.1、Spring是什么&#xff1f; Spring 是一款主流的 Java EE 轻量级开源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并创立&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的开发。从简单性、可测…

Android Compose Bloom 项目实战 (四) : 主页

1. 前言 上篇文章 我们实现了 Compose Bloom项目的开发页&#xff0c;这篇文章接着上文&#xff0c;来介绍主页的开发。 2. 分析页面布局 根据UI稿我们可知&#xff0c;这个页面有一个底部切换的BottomBar&#xff0c;还有一个搜索框&#xff0c;一个横向的列表以及一个竖向的…

RNN GRU模型 LSTM模型图解笔记

RNN模型图解引用RNN模型GRULSTM深度RNN双向循环神经网络引用 动手学深度学习v2–李沐 LSTM长短期记忆网络3D模型–B站up梗直哥丶 RNN模型 加入了一个隐变量&#xff08;状态)&#xff0c;隐变量由上个隐变量和上一个输入而更新&#xff0c;这样模型就可以达到具有短期记忆的效…

加油站会员管理小程序实战开发教程10

上一篇我们介绍了计算距离及到店导航的功能,本篇我们介绍一下今日油价的功能。 如果要按日显示最新的数据,那么我们首先需要有数据源来存放每日的油价数据。这里涉及数据源的时候要考虑你的数据是只录入一条,还是每日录入一条。 录入一条呢,比较简单,但有个问题是如果我…

制作for arm64 cpu架构的docker镜像

我前段时间买了个阿里云&#xff0c;没有留意CPU的架构是ARM的&#xff0c;结果部署系统的时候就发现出问题了&#xff0c;部署在docker里的容器实例根本跑不起来&#xff0c;提示什么执行文件格式错误&#xff08;“exec format error”&#xff09;。 究其原因&#xff0c;…

spring注解方式整合Dubbo源码解析

系列文章目录 前言 本节我们的Dubbo源码版本基于2.6.x 在前一章我们的整合案例中&#xff0c;我们有几个比较关键的步骤&#xff1a; 在启动类上标注了EnableDubbo注解在provider类上面标注了Service注解来提供dubbo服务在消费的时候通过Reference注解引入dubbo服务在配置文件…

软考中级-面向对象

面向对象基础&#xff08;1&#xff09;类类分为三种&#xff1a;实体类&#xff08;世间万物&#xff09;、接口类&#xff08;又称边界类&#xff0c;提供用户与系统交互的方式&#xff09;、控制类&#xff08;前两类之间的媒介&#xff09;。对象&#xff1a;由对象名数据&…

【jumpServer 功能梳理】

用户管理 1.1 用户列表 创建jumpServe 账号 ;角色分为用户 管理员&#xff1b;更新账号信息&#xff1b;查看用户详情以及授权的资产&#xff1b; 1.2 用户组 用户组&#xff0c;这个组的意义在于用一个统称对接资源&#xff1b;用户组包含多个用户&#xff0c;可以操作增加删除…

LeetCode初级算法题:两数之和+斐波拉契数列多种java解法

目录7 两数之和题目描述&#xff1a;解题思路与代码暴力解法&#xff1a;解法一&#xff1a;二分查找解法二&#xff1a;双指针2 斐波那契数列题目描述&#xff1a;解题思路与代码![请添加图片描述](https://img-blog.csdnimg.cn/d06a95d7989b4794bd7f5f02fbd6f87e.png)解法一&…

spring之使用Spring的AOP

文章目录前言一、准备工作1、添加相应的依赖2、添加相应的命名空间3、创建目标类4、创建切面二、使用AOP1.在切面类中编写增强代码以及切点表达式2、开启aspectj的自动代理3、测试类4、测试结果前言 Spring对AOP的实现包括以下三种方式 1、Spring框架结合AspectJ框架实现的AOP…

自抗扰控制ADRC之反馈控制律(NLSEF)

目录 前言 1.非线性状态误差反馈控制律(NLSEF) 1.1 控制律形式 1.2 控制量的生成(或者说扰动的补偿) 1.2.1补偿形式① 1.2.1补偿形式② 2.仿真分析 2.1仿真模型 2.2仿真结果 前言 前面的两篇博客依次介绍了TD微分跟踪器安排过渡过程、扩张观测器&#xff1a; 自抗扰…

用腾讯云同步Obsidian笔记

介绍 之前用gitee同步OB笔记&#xff0c;同时做图床。但由于git系产品设置起来相对复杂&#xff0c;且后续可能有外链过审等问题。周五被同事小姐姐安利了用腾讯云COS&#xff0c;试了一下&#xff0c;果然不错。其主要优点如下&#xff1a; 设置简单&#xff0c;学习成本低&…

WSL(Windows Subsystem for Linux)

一、WSL优势 •传统方式&#xff1a;获取Linux操作系统环境&#xff0c;必须安装完整的虚拟机&#xff0c;如VMware•WSL&#xff1a;以非常轻量化的方式&#xff0c;得到Linux系统环境总结&#xff1a;WSL更方便&#xff0c;简单、好用、轻量化、省内存 二、什么是WSL ①不…