后端(五):JVM

2023-11-13

目录

JVM 中的内存区域划分

JVM 的类加载机制

 1.  加载

2. 验证

3. 准备

4. 解析

5. 初始化

JVM 中的垃圾回收策略

找,确认垃圾

1. 引用计数

2. 可达行分析

释放”垃圾“对象

1. 标记清除

2. 复制算法

3. 标记整理

分代算法


JVM也就是我们俗称的八股文,作为一个普通的程序员工作中是基本不可能用到的;因为它设计的初衷就是为了让程序员能够比较简单的,感知不到系统层面的一些内容(很多时候,程序员只关注业务逻辑,不需要关注底层实现细节)。

数年前开始,JVM成为了Java程序猿必考的内容。

JVM里的内容非常多,大部分内容咱叶看不懂,JVM本来是写给C/C++ 程序员看的,它的底层实现都是 C/C++ 的代码,研究JVM 的也都是那一批人。

我们这里针对JVM的面试题,作出以下一些讨论。

本篇主要在于以下三点:

  1. JVM 中的内存区域划分
  2. JVM 的类加载机制
  3. JVM 中的垃圾回收策略

本章比的不是你了解多少,比的是你能背下来多少

JVM 中的内存区域划分

JVM 其实是一个 Java 进程, Java 进程 会从操作系统中申请一大块内存区域,给 java代码使用

而这一大块内存区域,就有我们之前 SE 阶段提到的:栈区、堆区、方法区(新版的也叫 元数据区)。

内存区域划分最最核心的部分:

  1. 堆区: new 出来的对象(成员变量)
  2. 栈区: 维护方法之间的调用关系(局部变量)
  3. 方法区/元数据区: 放的是类加载之后的类对象(静态变量)

一般这里的考点就是 给你一段代码,问你某个变量在哪个区。

我们主要就是看这个变量是个什么变量(局部变量,成员变量【注意被 final 修饰过的局部变量】,静态变量)

这里简单举个例子:

void func() {
    Test t = new Test();
}

 这里的 t 对象是个引用类型,t是个局部变量,所以是在栈上的的,而 new Test(),这个对象本体是在堆上的。至于func() 这个方法是存在方法区的,方法在内存中都是以二进制的方式存储的。

我们来看一张更细节的图:

我们在SE 阶段认识的在做细分 。

其中将栈区分为  本地方法栈 和 虚拟机栈 。

这两个栈也很好区分:

  1. 虚拟机栈,是给 Java 代码使用的
  2. 本地方法栈,是个JVM 内部的本地方法使用的,我们说 JVM 源码都是 C++ 实现的(可以简单理解为是给 C++ 使用的)

程序计数器

这个程序计数器是用来记录当前程序指令到了哪一个指令了。

上述的 堆区 和 元数据区 在一个 JVM 进程中只有一份。

而栈(本地方法栈和 虚拟机栈)和 程序计数器 是存在多份的,每一个 线程 都存在一份

JVM 的类加载机制

类加载其实就是 把 .class 文件,加载到内存中,得到 类对象 这个过程。

咱们 祖师爷(冯诺依曼)提出:程序运行,就需要把依赖的"指令和数据" 加载到内存中。

这个类加载的过程非常复杂(一般不需要我们理解)

《深入理解 Java虚拟机(第三版)》这本书中,将类加载总结成了 5 个词 (必备)

类加载的声明周期如下:

 1.  加载

加载其实就是找到 .class 文件,并且读取文件内容

这里涉及到一个非常经典的考点,双亲委派模型,这个等到类加载的最后来讲;

2. 验证

.class 文件有明确的数据格式(二进制的)

 源码中 都有一个 ClassFile 来体现一个类有哪些信息

3. 准备

给类对象 分配内存空间(这里还没有走到 初始化阶段,所以这里的内存空间都是全 0 的)

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。

比如此时有这样一行代码:
        public static int value = 123;
它是初始化 value 的 int 值为 0,而非 123。

4. 解析

解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程
这里涉及到 将 符号引用 替换为 直接引用 的过程

我们先来说说符号引用

符号引用就是 字符串常量,我们在 验证 阶段不是加载好了 .class 文件嘛,.class 文件存在了 字符串常量,我们这里就能直到它的相对位置(偏移量),但是并不知道它的实际位置。

这个时候的字符串常量就是 符号引用。

直接引用

当真正加载到内存中,就会把字符串常量填充到内存中的特定地址上;

字符串常量之间的相对位置还是一样的,但是这些字符串有了自己真正的内存地址,此时的字符串就是直接引用。

5. 初始化

其实 4 和 5 可以并做一步,但是人家作者规定了 将其分为两步。

解析是初始化了 字符串常量,而这一步是 初始化 对象【除字符串常量部分】(初始化静态成员,执行静态代码块、如果类存在父类,还需要加载父类)

ok,到这里 上述 五步 也就讲完了。

类加载这个步骤,啥时候会触发呢?

并非 jvm 一启动,就会把所有的 .class 都加载了,整体采纳了 (懒汉设计模式)的策略,非必要不加载。

啥叫必要

  1. 创建了这个类的实例
  2. 使用了这个类的静态  方法/属性
  3. 使用了这个类的子类

总之就是与这个类相关的类、属性、方法、实例化对象...

这里还有一个最关键的考点:双亲委派模型

这个模型所做的就是 加载这个步骤中,找一个 .class 文件这个过程

事实上,这个模型并非是类加载中一个很重要的步骤,但是是个非常重要的考点

JVM 中,加载类,需要用到一组特殊的模块:类加载器

在 JVM 中,内置了三个类加载器

BootStrap ClassLoader 负责加载 Java标准库中的类

Extension ClassLoader 负责加载一些非标准的类,但是 是sun/Oracle 扩展的库的类

Application ClassLoader 负责加载项目中自己写的类,以及第三方库 中的类

当具体加载一个类的时候,其过程如下:

双亲?上面明明就一个 null ,哪里来的双亲?

这个就是个翻译问题,parent 表示双亲中的一个,我们翻译为双亲罢了。

这个双亲委派模型也是可以打破的,自己实现的类加载器,是否遵守上述规则,看个人设计。

JVM 中的垃圾回收策略

垃圾回收机制 也可以叫 GC 回收机制

这个可以帮助程序员自动释放内存

在 C语言中,malloc 需要手动 free,否则就会出现内存泄漏(光申请,不释放,内存用完了,程序也就完了)

Java 等后继编程语言,都采用了 GC 来解决上述问题,能够有限减少内存泄漏出现的概率。

内存的泄露是个比较纠结的问题:

申请的时机是明确的 => 使用到了必须申请;

释放的时机是模糊的 => 彻底不使用了才能释放

啥叫彻底不使用了:没有引用指向它

JVM 中的内存有好几个区,我们要释放的就是 (new 出来的)

我们也来随手聊聊其他区的释放:

  1. 程序计数器,就是个单纯存地址的整数,不要了就直接随着线程一起销毁。
  2. 栈,也是随着线程一起销毁的,方法调用完毕,方法的局部变量自然随着出栈的操作销毁了。
  3. 元数据区/方法区,村的类对象,很少会“卸载”。
  4. 堆,是GC的主要目标,GC也是以对象为单位进行释放的(说是释放内存,本质就是释放对象)

GC 中主要分为两个阶段:

  1. 找,谁是垃圾
  2. 释放,将垃圾对象释放掉

上述两个阶段,主要是了解清楚垃圾回收的算法,这些算法 并不代表 JVM真实的实现方法,现在的JVM 在这些基本算法之上又做出了很多细节的调整和优化。

找,确认垃圾

什么是垃圾,后续不会再使用到的,就是垃圾,Java中使用一个对象,只能通过引用,如果一个对象没了引用就可以确定它是垃圾了。

Java中只是单纯的通过引用没有指向这个操作,来判定垃圾。

单纯的通过引用可能会照成 垃圾释放不及时,但这都是小事;就怕释放太快,将还有引用的对象释放掉,这是大事。

具体来说说,Java怎么样直到一个对象是否还有引用呢?

1. 引用计数

给对象安排一个而外的的空间,保存一个整数,表示该对象有几个引用

(事实上,Java并没有采用这个方案,反倒是 python和PHP采用了)

借助图片来看看:

随着引用的增加,计数器就增加,引用的销毁计数器就销毁。

当,计数器为0,就认为没有了引用,于是就是垃圾了

每个计数器都开辟一个空间, 上述之开辟一个空间,是因为都是同一类型 Test,我要是有其他类型,例如Cat 那么还需要开辟一个空间。

因此,这种方法会出现两个问题:

  1. 对象类型过多,那么就会非常浪费空间
  2. 存在循环引用的情况,那么就会导致引用计数的判定的逻辑出错

假设,由上述这个栗子,此时,a 和 b 销毁了,这个时候,两个对象的引用计数各自减 1 :

此时,这两个引用计数还在相互引用,并不是 0 ,所以不能作为垃圾,但是这个两个对象都不可以再使用 。

2. 可达行分析

可达行分析将对象之间的引用关系,理解成了一棵树形结构,从一些特殊的起点出发,进行遍历,只要能遍历访问到的对象,就是“可达的“,其余”不可达“ 的就作为垃圾处理掉。

 此时,通过 root 这个引用,就可以访问到整个树的任意结点,通过上述方式,root就能引用到所有结点。

如果这里的 e 突然为 null ,g是否就是不可达呢?

不对,既是e 为 null 了,还会存在其他指向指向g,g 任然是可达的。

可达性分析关键要点,进行上述遍历,需要有”起点“

  1. 栈上的局部变量(每个栈的每个局部变量,都是起点)
  2. 常量池中的引用的对象
  3. 方法区中,静态成员引用的对象

可达性分析,总的来说,就是从所有的 gcroots 的起点触发,看看该对象里又通过引用能访问哪些对象,顺腾摸瓜,把所有可以访问的对象都遍历一遍(遍历的同时把对象标记成为”可达“)

可达性分析,克服了引用计数的两个缺点,但是它也存在自身的问题

  1. 这个树有高度,搜易搜索会消耗更多的时间,因此某个对象成为垃圾,不一定能够第一时间发现,扫描会消耗时间
  2. 再进行可达性分析的时候,要顺着树进行搜索,一旦这个过程中,当前代码出现了变化,就更复杂了

因此,为了更准确的完成这个 扫描过程,还需要其他业务暂停工作(STW问题)

所谓的 STW 也就是 stop the world ; 这个是可达性分析最最被诟病的问题,Java发展了这么多年,垃圾回收这个也在不断的更新优化,STW 这个问题,现在以及能够比较好的应对了,但是并不能完全消除,已经可以让 STW 的时间大大缩短了。

上述已经解决了理论的找垃圾了,接下来就是释放垃圾

释放”垃圾“对象

三种典型的 策略

1. 标记清除

"标记-清除"算法是最基础的收集算法。算法分为"标记"和"清除"两个阶段 : 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象:

如图所示, 画了勾的就是我们需要释放的;

我们这块空间很难被重复利用,我们申请的”整块的连续的空间“现在这里空闲的空间都是离散的,有自己独立的空间。

总的空闲的空间 可能超过 1个 G,但是你想申请 500M 都不一定能够申请到(因为他们都是散的)。

"标记-清除"算法的不足主要有两个 :

  1. 效率问题 : 标记和清除这两个过程的效率都不高
  2. 空间问题 : 标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集

2. 复制算法

我们把整个内存空间,分为两段,一次只使用一半:

还是一样,花了勾的属于垃圾;

我们将不属于垃圾的复制到另一半空间中去,剩下的全部释放掉:

复制算法虽然解决了内存碎片的问题,但是也存在相关的缺点:

  1. 内存利用率低
  2. 如果当前的对象大部分都是要保留的,垃圾很少,此时复制成本很高

3. 标记整理

类似于顺序表删除中间的元素:

我们将 有效元素往前搬

随后将搬运处的空间释放 

该算法虽然解决了内存碎片问题,但还存在一些问题:

  1.  搬运的开销比较大

 事实上, JVM 的实现思路,是上述集中的结合,针对不同情况下取长补短:

分代算法

基本思想:给每个对象设置”年龄“ ,这个概念,描述对象存在多久了,如果是一个对象刚刚诞生,认为是 0 岁,经过每一轮扫描(可达性分析),没被标记成垃圾,就长大一岁

通过描述年龄来表示对象存活时间 

算法执行步骤:

  1. 1. 新创建的对象,放到伊甸区,当垃圾回收扫描到伊甸区之后,绝大部分对象都会在第一轮 GC 中被干掉
  2. 如果伊甸区的对象,熬过第一轮,通过复制算法,拷贝到生存区,生存去分为两半,一次只是用一半,垃圾回收扫描伊甸区的对象,也是发现垃圾就淘汰,不是垃圾就复制到另一半
  3. 当这个对象熬过多轮,年龄增长到一定程度,通过复制算法拷贝到老年代
  4. 进入老年代,年龄都挺大了,再消亡的概率小于前面的新生代,针对老年代的 gc 扫描概率小很多,如果发现老年代某个对象是垃圾,使用标记整理的方式清楚
  5. 特殊情况:某个对象很大,直接存放到老年代,因为这个对象搬运起来的开销很大,不适合多次搬运

这些都只是基本思想,具体的实现再这些基础之上,还做出了很多改进和优化;

Java的版本在变,垃圾回收器也会不断变化。

本篇的八股就到这里,校招应该不会考那么多八股文,一定要把这些背下来!!!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

后端(五):JVM 的相关文章

  • 如何在 IntelliJ 中设置 VM 内存?我需要单独设置 Tomcat 内存选项吗?

    我正在做一些基准测试 我想知道如何为 IntelliJ 和 Tomcat 设置内存 在 IntelliJ 的右下角我看到 98M 或 147M 这是做什么用的 我如何知道我是否为tomcat分配了足够的内存 在其 VM 选项文件中设置 In
  • 如何限制Java 8应用程序消耗的总内存?

    为了限制 Java 7 应用程序消耗的总内存 我可以使用以下公式 取自本文 https plumbr eu blog why does my java process consume more memory than xmx 最大内存 Xm
  • Java中的线程何时从内存中删除? [复制]

    这个问题在这里已经有答案了 来自 Java API 文档 Java虚拟机继续执行线程 直到遵循 发生 所有非守护线程的线程都已死亡 或者通过返回 从调用 run 方法或抛出异常 传播到 run 方法之外 我希望我的假设是正确的 一旦线程完成
  • 当JVM执行Java应用程序时,操作系统的作用是什么?为什么我们需要操作系统?

    我在网上读过一些资料 有人说Java应用程序是由java虚拟机 JVM 执行的 执行 这个词让我有点困惑 据我所知 非Java应用程序 即 用C C 编写 可以由操作系统执行 在较低级别 这意味着操作系统将二进制程序加载到内存中 然后指示C
  • 非线性条件断点

    是否可以设置断点 使程序在指令满足某些条件后停止执行true 一个类有一个名为的变量currency我想设置一个断点 使程序在之后的任何行停止currency 20 我不知道行号在哪里currency已更改 因此这就像在其中放置一个断点每行
  • JVM 内存类型

    我正在做一个监控项目 我们有监控软件正在运行并从服务器重新收集指标 一切工作正常 但我们需要一些有关 JVM 内存使用情况详细信息 我们有一些具有不同内存类型的列 我们需要知道这些是什么 Heap Non Heap Usage Peak C
  • IntelliJ 调试:暂停整个虚拟机,然后进入单线程

    我正在调试一个具有大量线程的应用程序 我的断点设置为暂停整个虚拟机 当线程遇到其中一个断点时 我想使用 Step Over 但这似乎会恢复整个虚拟机 直到该步骤完成 如果我可以只单步执行到达断点的单个线程 那确实会有帮助 在 Intelli
  • Java VM 突然退出且没有明显原因

    我的 Java 程序突然退出 没有抛出任何异常 也没有正常完成 这是一个问题 我正在写一个程序来解决欧拉计划 http projecteuler net s 这就是我得到的 private static final int INITIAL
  • 如何使用IntelliJ IDEA ThreadDumpVisualizer插件分析Java线程转储

    我正在寻找使用一些线程转储分析器来分析 Java 线程转储并安装了ThreadDumpVisualizerIntelliJ IDEA 插件 但不知道如何使用它 插件页面 https plugins jetbrains com plugin
  • Cassandra DB 中的日期插入:重要的 1 小时轮班问题(后续)

    这是这个的后续其他原帖 https stackoverflow com questions 23080188 date insertion in cassandra db non trivial 1h shift issue 2308355
  • Lambda 性能改进,Java 8 与 11

    我对 lambda 与方法参考运行了一些 JMH 测试 看起来类似于 IntStream reduce Integer max vs IntSream reduce i1 i2 gt Integer max i1 i2 我注意到 在 Jav
  • JVM HotSpot 上的 Java 异常计数器

    我想知道是否可以在不更改应用程序代码的情况下记录 JVM 级别上发生的每个异常 我所说的每个异常是指捕获和未捕获的异常 我想稍后分析这些日志并按异常类型 类 对它们进行分组 并简单地按类型对异常进行计数 我正在使用热点 也许有更明智的理由这
  • 热点 JVM 字节码解释器是跟踪 JIT 吗?

    这个问题几乎说明了一切 我一直在寻找答案 甚至通过 VM 规范 但我没有明确说明 No 不过 还有一些其他 JVM 具有跟踪 JIT HotPath http HotPath GoogleCode Com and Maxine http L
  • 如何查看JVM中JIT编译的代码?

    有什么方法可以查看 JVM 中 JIT 生成的本机代码吗 一般用法 正如其他答案所解释的 您可以使用以下 JVM 选项运行 XX UnlockDiagnosticVMOptions XX PrintAssembly 根据特定方法进行过滤 您
  • 最近有关于 JVM 的书吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • STS 无法在我的计算机上启动

    我试图在 eclipse 上设置 Spring mvc 项目 基本项目进展顺利 但是使用 Restful 服务 Jersey 等开始出现许多与依赖项相关的错误 所以我打算转到STS 我正在使用 STS 2 9 2 它给我 无法创建java虚
  • HotSpot使用的Mark-Compact算法是什么?

    当阅读 Mark Compact 章节时垃圾收集手册 https rads stackoverflow com amzn click com 1420082795 提出了一系列替代方案 但其中大多数看起来很旧 理论上 例如 2 指压缩和 L
  • 什么触发了java垃圾收集器

    我对 Java 中垃圾收集的工作原理有点困惑 我知道当不再有对某个对象的实时引用时 该对象就有资格进行垃圾回收 但是如果它有对实时对象的引用怎么办 可以说我有一个节点集合 它们再次引用更多节点 List 1 gt Node a gt Nod
  • 启用JConsole远程监控是否会影响生产中的系统性能?

    Oracle Sun 说只要不在生产环境中本地运行就可以吗 http download oracle com javase 1 5 0 docs guide management jconsole html http download or
  • 在intellij中为java启用ssl调试

    从我的问题开始 上一期尝试通过 tls ssl 发送 java 邮件 https stackoverflow com questions 39259578 javamail gmail issue ready to start tls th

随机推荐

  • 时间和日期

    Boost使用的timer和data timerj进行对应和时间日期相关的出来文档 timer包含三个组件 分别为timer progress timer以及对应的progress display timer timer可以测量运行时间 t
  • ROS系统基本功能的使用详解(基本指令/节点/服务/启动文件/动态参数)

    ROS系统基本功能的使用详解 一 创建工作空间 二 创建与编译ROS功能包 三 ROS的基本命令 3 1 节点 3 2 主题 3 3 服务 3 4 参数服务器 四 节点的创建与运行 4 1 创建源文件 4 2 修改CMakeLists tx
  • 域名+七牛云+PicGo+pypora

    域名 七牛云 PicGo pypora 前提准备 域名 自己的域名 七牛云 免费注册申请10G空间够用 picGo 地址 pypora 自行下载 GO 七牛云 注册 gt 登录 gt 控制台 找到对象存储 新建自己空间 绑定域名 添加域名自
  • STM32使用SPI通信驱动2.4G无线射频模块发送数据

    目录 SPI介绍 SPI接口原理 SPI工作原理 SPI特征 引脚配置 结构体 库函数 SPI配置过程 SPI h SPI c NRF24L01无线射频模块 NRF24L01厂家驱动代码移植 NRF24L01 h NRF24L01 c ma
  • 分析一个别人的qt+opengl例子

    Qt5 OpenGL学习笔记 用Qt封装的QOpenGL系列绘制有颜色有深度的三角形 最近学习OpenGL 虽然说Qt可以使用原生OpenGL的API 但是Qt也提供了封装的QOpenGL系列 我用原生的和封装的分别实现了一次简单渲染 都是
  • 竞赛 基于卷积神经网络的乳腺癌分类 深度学习 医学图像

    文章目录 1 前言 2 前言 3 数据集 3 1 良性样本 3 2 病变样本 4 开发环境 5 代码实现 5 1 实现流程 5 2 部分代码实现 5 2 1 导入库 5 2 2 图像加载 5 2 3 标记 5 2 4 分组 5 2 5 构建
  • Python Web系列学习2-Django

    1 django admin Django项目管理工具 建立一个Django项目用 django admin startproject xxx 生成的站点目录结构为 2 进入站点目录 建立一个应用 python manage py star
  • Qt基础篇:Qt读取路径下所有文件或指定类型文件(含递归、判断是否为空、创建路径)

    文件路径的拆解 QFileInfo fileinfo QString file full ui gt m AlgorithmFilePathLineEdit gt text qDebug lt lt file full 输出1 filein
  • Java框架体系架构的知识,分享一点面试小经验

    前言 当前我们都会说SpringBoot是Spring框架对 约定优先于配置理念的最佳实践的产物 一个典型的SpringBoot应用本质上其实就是一个基于Spring框架的应用 而如果大家对Spring框架已经了如指掌 那么 在我们一步步揭
  • Python实现截图——附完整源码

    Python实现截图 附完整源码 为了能在日常工作中方便地截取并保存屏幕截图 我们可以利用Python编写一段代码实现这个功能 本文将介绍基于Windows平台下的Python截图实现方法 包括如何使用Python的Pillow模块以及py
  • YOLO8添加facial landmark和Head Pose的评价逻辑

    目录 TOC 目录 前言 一 如何在val py中添加NME的逻辑 二 在val py中添加Angle Eorror的逻辑 1 引入库 三 将AFLW2000转为yolo格式 1 参考ultralyticsFaceMark process3
  • JAVA开发环境JDK安装及配置

    一 安装JDK 获取JDK的安装包 1 通过官网下载 2 打开安装包 开始安装JDK和JRE 1 打开JDK安装包 2 点击下一步开始JDK安装 3 更改安装路径 接下来以我的电脑为例安装到E盘 其他盘同理 4 将文件夹路径改到E盘新建的文
  • 用js动态创建svg

    吃水不忘挖井人 svg基础教程https www bilibili com video BV1Pt411y7V6 p 1 要实现的效果 svg文件的写法
  • 【LSTM回归】基于粒子群优化注意力机制的长短时记忆神经网络PSO-attention-LSTM实现数据回归预测附matlab代码

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab完整代码及仿真定制内容点击 智能优化算法 神经网络预测 雷达通信 无线传感器
  • MySQL之分表分库分区

    数据库分表可以解决单表海量数据的查询性能问题 分库可以解决单台数据库的并发访问压力问题 分表 分表分为水平分表和垂直分表 水平分表原理 分表策略通常是用户ID取模 如果不是整数 可以首先将其进行hash获取到整 水平分表遇到的问题 1 跨表
  • Hadoop序列化案例

    Hadoop序列化案例 统计每一个手机号耗费的总上行流量 总下行流量 总流量 数据 1 13736230513 192 196 100 1 www baidu com 2481 24681 200 2 13846544121 192 196
  • Kafka3.0.0版本——Leader Partition自动平衡

    目录 一 Leader Partition自动平衡的概述 二 Leader Partition自动平衡的相关配置参数 三 Leader Partition自动平衡的示例 一 Leader Partition自动平衡的概述 正常情况下 Kaf
  • 代码审计练习题

    代码审计练习题 源码 方法 简单记录一下姿势 源码 判断var1和var2是否为对象 用弱不等号判断 分别判断md5
  • 将CSDN文章导出为.md、HTML、pdf格式

    将CSDN文章导出为 md HTML pdf格式 一 将CSDN文章导出为 md文件 二 将CSDN文章导出为HTML文件 三 把 md文件转换为pdf格式 一 将CSDN文章导出为 md文件 1 打开一篇CSDN文章 点击上方的 导出 按
  • 后端(五):JVM

    目录 JVM 中的内存区域划分 JVM 的类加载机制 1 加载 2 验证 3 准备 4 解析 5 初始化 JVM 中的垃圾回收策略 找 确认垃圾 1 引用计数 2 可达行分析 释放 垃圾 对象 1 标记清除 2 复制算法 3 标记整理 分代