【JVM系列】- 寻觅·方法区的内容

news2024/11/17 7:49:57

寻觅·方法区的内容

😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🌝分享学习心得,欢迎指正,大家一起学习成长!

在这里插入图片描述

文章目录

  • 寻觅·方法区的内容
    • 堆、栈、方法区的交互关系
    • 方法区的概念
      • 了解方法区
      • 设置方法区大小
        • jdk1.7及以前
        • jdk1.8及以后
      • OOM问题
    • *方法区的内部结构
      • 类型信息
      • 域(Field)信息
      • 方法(Method)信息
      • 常量池与运行时常量池
        • 常量池(Constant Pool)
        • 运行时常量池(Runtime Constant Pool)
        • 常量池与运行时常量池的区别
      • 通过字节码看结构
      • *方法区的演进
        • JDK1.6之前
        • JDK1.7
        • JDK1.8之后
        • 永久代为何被替换呢?
        • 字符串常量池(StringTable)为什么要做调整呢?
    • 方法区的垃圾回收机制
    • 总结

堆、栈、方法区的交互关系

在学习方法区之前已经是学习了堆和栈,现在我们就来回顾一下,来看看三者的交互关系是怎样的。
栈内存是用于存储方法的局部变量、形参和方法调用的状态信息。当一个方法被调用时,Java虚拟机会在栈内存中为该方法创建一个栈帧,用于存储方法的局部变量、形参等信息。当方法执行完毕后,该栈帧会被销毁。
堆内存是用于存储Java对象和数组。当一个对象被创建的时候,JVM会在堆内存中为该对象分配一块内存空间,用于存储对象的实例变量。对象的引用则会存储在栈内存中。当没有任何引用指向该对象时,该对象所占用的堆内存空间会被垃圾回收器回收。
方法区(Method Area)用于存储被虚拟机加载的类信息、常量池、静态变量等。方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样可以是不连续的。方法区的大小,跟堆空间一样,可以选择固定大小或者可拓展。未命名文件 (16).png
在Java栈中的本地变量表中存放的是对象的引用地址,指向的是Java堆中的对象实例数据,在对象实例数据中有个到对象类型数据的指针,这个指针会指向这个类的类型数据,而这个类的类型结构就是被加载到方法区中。

方法区的概念

方法区在逻辑上是属于堆的一部分,但是在一些简单的实现可能不会选择去进行垃圾收集或进行压缩。但是对于HotspotJVM而言,方法区还有一个别名:Non-Heap(非堆),目的就是要和堆分开。方法区看作是一块独立于Java堆的内存空间。

了解方法区

  • 方法区(Method Area)与 Java 堆一样,是所有线程共享的内存区域。
  • 方法区(Method Area)是一块用于存储类信息、常量、静态变量、即时编译器优化后的代码等数据的内存区域。在不同的JVM实现中,方法区也被称为永久代(Permanent Generation,在Java 7及之前的版本中),或者是在Java 8及以后的版本中,被元数据区(Metaspace)取代。
  • 方法区在JVM启动的时候就会被创建,实际物理内存空间和Java堆区是一样都可以不连续。并且方法区的空间大小也是可以选择固定或者可扩展。
  • 方法区也是有内存溢出错误,当定义的类过多,导致方法区溢出,虚拟机会抛出OutOfMemoryError错误。
  • 在关闭JVM就会释放这个方法区的内存。

我们通过Java VisualVM就能看到方法的占用情况
在这里插入图片描述

设置方法区大小

方法区的大小可以通过参数来设置固定大小,不设置就是根据应用的需要动态调整。

jdk1.7及以前
  • 通过-XX:PermSize来设置永久代初始分配空间。默认是20.75M
  • 通过-XX:MaxPermSize来设置永久代最大可分配空间(32位默认64M,64位默认82M)。
  • 当JVM加载的类信息超过了这个值,就会报OutOfMemoryError:PermGen space
jdk1.8及以后
  • 元数据区大小可以使用参数-XX:MetaspaceSize-XX:MaxMetaspaceSize指定,替代上述原有的两个参数。
  • 默认值是与平台有关系,在windows下,-XX:MetaspaceSize是21M,-XX:MaxMetaspaceSize的值是-1,代表没有限制。
  • 与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。如果元数据发生溢出,虚拟机一样会抛出异常OutOfMemoryError:Metaspace
  • -XX:MetaspaceSize :设置初始的元空间大小。对于一个 64 位的服务器端 JVM 来说,其默认的 -XX:MetaspaceSize 的值为20.75MB,这就是初始的高水位线,一旦触及这个水位线,Full GC 将会被触发并卸载没用的类(即这些类对应的类加载器不再存活),然后这个高水位线将会重置,新的高水位线的值取决于 GC 后释放了多少元空间。如果释放的空间不足,那么在不超过MaxMetaspaceSize时,适当提高该值。如果释放空间过多,则适当降低该值。
  • 如果初始化的高水位线设置过低,上述高水位线调整情况会发生很多次,通过垃圾回收的日志可观察到 Full GC 多次调用。为了避免频繁 GC,建议将 -XX:MetaspaceSize 设置为一个相对较高的值。

OOM问题

从Java 8开始,随着永久代的去除,方法区OOM的问题在很大程度上得到缓解。在Java 8及以后的版本中,采用元数据区,可以根据应用程序的需要动态调整内存大小,从而更好地适应不同的应用场景。

OOM的排查与解决:

  • 可以使用JVM监控工具,例如VisualVM、JConsole或jstat,来监控方法区的使用情况。通过监控工具,你可以观察方法区的内存使用情况,及时发现潜在的OOM问题。在应用程序中,尤其是大型或长时间运行的应用程序中,可能会发生内存泄漏,导致方法区不断积累无用的类信息。通过内存分析工具,如Eclipse Memory Analyzer(MAT)或YourKit等,可以检查并解决潜在的内存泄漏问题。
  • 优化应用程序代码和配置,尽可能减少类的加载和卸载次数,合理使用缓存,以降低对方法区的压力。

*方法区的内部结构

方法区的内部结构包括常量池(Constant Pool)、类信息(包括接口、注解、方法等等信息)、静态变量、即时编译器生成的代码、运行时常量池等。
方法区的信息存储:

《深入理解Java虚拟机》书中对方法区存储内容的表述是:用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。随着jdk版本的不一样,对于这些存储信息也会有稍微的改变。

类型信息

方法区存储了加载的每个类的结构信息,包括类的字段、方法、父类、接口等。每个加载的类都有一个对应的Class对象,该对象包含了类的元信息。

对每个加载的类型(类 class、接口 interface、枚举 enum、注解 annotation),JVM 必须在方法区中存储以下类型信息:

  1. 这个类型需要是完整的类名(全限定名:包名.类名)
  2. 对于此类型的直接父类是需要完整有效名(对于interface或者java.lang.Object,都是没有父类)
  3. 这个类型的修饰符(public,abstract,final的某个子集)
  4. 这个类型直接接口的一个有序列表。(比如说一个接口实现了多个接口,这些被实现的接口是有序的)

域(Field)信息

  • JVM 必须在方法区中保存类型的所有域的相关信息以及域的声明顺序。
  • 域的相关信息包括:域名称、域类型、域修饰符(public、private、protected、static、final、volatile、transient 的某个子集)

对于静态变量(类变量),它们的信息除了存储在方法区中,还会在类加载时被分配在堆内存中,而不是对象实例的内存中。这是因为静态变量是属于类的,而不是对象的。

方法(Method)信息

方法信息包括类中的各种方法的相关数据,这些数据描述了方法的签名、访问修饰符、返回类型、方法体的字节码等。以下是方法区中存储的方法信息的一些关键点:

  • 方法名称
  • 方法的返回类型
  • 方法参数的数量和类型(需要按顺序)
  • 方法的修饰符(public,private,protected,static,final,synchronized,native,abstract 的一个子集)
  • 方法的字符码(bytecodes)、操作数栈、局部变量表及大小(abstract 和 native 方法除外)
  • 异常表(abstract 和 native 方法除外)
    • 每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏移地址、被捕获的异常类的常量池索引。

常量池与运行时常量池

常量池和运行时常量池都是用于存储字面量常量和符号引用的地方,但是二者是存在一些区别的。在方法区中,包含了运行时常量池(Runtime Constant Pool),要了解运行时常量池,就得先来了解一下常量池。

常量池(Constant Pool)

常量池是方法区的一部分,用于存储编译期生成的字面量和符号引用。常量池包括类和接口的全限定名、字段和方法的名称和描述符、字符串常量等。常量池是Class文件结构的一部分,但在加载到方法区时,它被存储为JVM的内部数据结构。

我们来了解一下常量池,它是在编译阶段由编译器生成并存储在 .class 文件中的一部分。也就是说,常量池虽然也是存储字面量和符号引用的地方,但是它主要是在编译期间确定的。所谓常量池,简单来说可以理解成一张表,虚拟机指令可以根据此表找到类名、方法名、参数类型、字面量等信息。
通过jclasslib这个idea插件可以直接查看字节码文件,可以从图中看到所谓的常量池,里面存储的类名等信息,开头[01]就是对应的常量池位置,例如#11也就对应常量池[11]
在这里插入图片描述

为什么需要常量池?

一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述信息外,还包含一项信息那就是常量池表(Constant Pool Table),包含各种字面量和对类型、域和方法的符号引用。

一个 Java 源文件中的类、接口,编译后产生一个字节码文件。而 Java 中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里,换另一种方式,可以存到常量池,这个字节码包含了指向常量池的引用。在动态链接的时候用到的就是运行时常量池。
在这里插入图片描述

如上图所示,字节码中链接#2对应的位置就是常量池中的[02]数据。

运行时常量池(Runtime Constant Pool)

运行时常量池与常量池相对应,运行时常量池是方法区的一部分,用于存储一些动态生成的常量,例如String对象的intern()方法生成的字符串常量。

  • 运行时常量池(Runtime Constant Pool)是在类加载阶段,就会创建对应的运行时常量池,将常量池的信息加载到内存中的一部分,属于方法区的一部分。
  • 常量池表(Constant Pool Table)是 字节码文件的一部分,用于存储编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
  • JVM 为每个已加载的类型(类或接口)都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。
  • 运行时常量池中包含各种不同的常量,包括编译器就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或字段引用。此时不再是常量池中的符号地址了,这里将是转换为真实地址。
  • 运行时常量池的内容可能会因为类的动态加载,这也就是运行时常量池相对于字节码文件常量池的另一个重要特征是:动态性
  • 当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则 JVM 会抛出 OutOfMemoryError 异常。
常量池与运行时常量池的区别

在 JVM 的方法区内部结构中,常量池和运行时常量池都是重要的组成部分。常量池在编译期确定,它包含了类的基本信息;而运行时常量池则在运行时加载,用于支持类的动态特性。运行时常量池通常也被认为是方法区的一部分。
二者的主要区别是:

  • ①常量池是 Java 类文件(.class 文件)的一部分,在编译期由编译器生成;常量池的数据在编译时已经确定,是类文件的一部分,不随着程序的运行而改变。
  • ②运行时常量池是在类加载阶段,将常量池的信息加载到内存中的一部分,属于方法区的一部分;运行时常量池的内容可能会因为类的动态加载、反射等操作而发生变化。

通过字节码看结构

接下来,我们使用一个demo,通过jclasslib来查看字节码信息,从而了解方法区的结构。
可以通过jclasslib插件也可以通过命令获取到字节码信息,这里我先将两种的方式做个比较。
首先使用命令来进行反编译,我们要先找到.class文件,并且将数据输出到txt文件中,命令如下:

# 切换到相应的地址
cd .\target\classes\com\lyd\testboot\jvm\
# 反编译
javap -v -p .\MethodAreaStructure.class > methodStructure.txt

我们来看一下两者数据的体现,都是用来查看反编译后的字节码信息。
在这里插入图片描述

首先,我们可以从jclasslib中看到,记录了父类以及实现的接口的类型信息,而这些数据都指向着常量池对应的索引。这些数据都会在classload加载到方法区中。

*注:加载到方法区中的类里面是记录了是哪个类加载器加载的,类加载器也会记录加载过哪些类。

在这里插入图片描述

接下来,我们看一下域信息,这些信息也是有classload加载到方法区中。其记录了域名称、域类型、域修饰符,并且这些都是有先后顺序的。
在这里插入图片描述

接着我们继续看方法,这里需要注意的是,在代码中并没有显式声明,但在编译的时候会自动加上无参构造方法,也就是对应着<init>,从jclasslib可以看到还有一个方法<clinit>,这是类的静态初始化块(static initializer),用于静态成员的初始化。
通过jclasslib来介绍一下方法信息还存储了什么,具体是怎么使用的。
在这里插入图片描述

为了方便查看这些都是什么信息,我这里将行号表、局部变量表的信息都截图粘在旁边,方便对应。首先,方法区还记会记录了栈的最大深度和局部变量表最大槽数。具体这些是对应了什么,笔者在之前的文章《探索·数据区的私有结构》都做了详细介绍,这里就不再做过多的赘述。
与javap输出的数据是一样的,只是用了不用的展示方式。

public void count();
  descriptor: ()V
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=2, args_size=1
       0: iconst_0
       1: istore_1
       2: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       5: iload_1
       6: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
       9: return
    LineNumberTable:
      line 20: 0
      line 21: 2
      line 22: 9
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      10     0  this   Lcom/lyd/testboot/jvm/MethodAreaStructure;
          2       8     1 count   I

还有一个重要的是,异常的情况。如下图,通过jclasslib中,在exceptionTest#Code下会多出一个StackMapTable(堆栈映射表)。 主要记录了在字节码的特定位置处的栈帧映射帧信息。每个栈帧映射帧描述了该位置处的局部变量表、操作数栈的类型状态,以及控制流的信息。
在Code中,能够看到异常表信息。里面会记录了异常开始的PC地址和结束的PC地址,以及触发异常之后需要跳转的PC地址,在通过行号表可以根据PC指向的地址对应到行号。
在这里插入图片描述

这里还需要注意的就是non-final的类变量

  • 静态变量和类关联在一起,随着类的加载而加载,成为类数据在逻辑上的一部分。
  • 类变量被类的所有实例共享,即使没有共享也能访问到。

例如一个简单的例子。我们定义一个静态变量,我们没有实例MethodAreaStructure对象,而是通过MethodAreaStructure.string的方法获得到这个字符串数据。即便我们创建了个null的对象,也能获得到。

public static void main(String[] args) {
    MethodAreaStructure methodAreaStructure = null;
    System.out.println(MethodAreaStructure.string);
    System.out.println(methodAreaStructure.string);
}

还有一种就是全局常量,使用static final修饰的。
被声明为final的类变量的处理方法则不同,每个全局常量在编译的时候,就已经会被分配了。

对于方法区的使用,字节码的PC包括本地变量表的变化是如何的,笔者在《探索·数据区的私有结构》一文中做了简单的介绍,后续再来补充细致化的描述。

*方法区的演进

Hotspot方法区的演变过程:(只有Hotspot才有永久代)

jdk1.6及之前有永久代,静态变量存放在永久代上
jdk1.7有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中
jdk1.8及之后取消永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆中
JDK1.6之前

在jdk1.6之前,方法区的落地是基于永久代(PermGen实现),其中包含了类型信息、域信息、方法信息、JIT代码缓存、静态变量和字符串常量池。
在这里插入图片描述

JDK1.7

在JDK1.7的时候,方法区的落地还是基于永久代(PermGen实现),内容的信息耶大多都不变,只不过就是把静态变量和字符串常量池提取到堆空间中了。所使用的内存还是虚拟机的内存,跟物理内存是存在着映射关系。
在这里插入图片描述

JDK1.8之后

在JDK1.8之后啊,就开始将永久代替换成了元数据区(Metaspace)来实现。使用的就不再是虚拟机内存,而是直接使用了物理内存,直接影响上限的是本地内存了。
在这里插入图片描述

永久代为何被替换呢?

替换永久代的动机可以通过官网找到答案,JEP 122: Remove the Permanent Generation, 找到Motivation标题的那段话,因为JRockit和Hotspot进行了融合,而JRockit客户不需要配置永久生成(因为JRockit没有永久生成),并且习惯于不配置永久生成,也就这样,所以永久代最后就被替换成了元数据区。
改动也是有必要的:

  • 永久代设置空间大小是很难确定的。如果动态加载很多类,就会很容易出现Perm区的OOM。而元空间并不在虚拟内存中,它依靠的是本地内存,所以,元空间在默认情况下只受本地内存的影响。
  • 对永久代进行的调优是很困难的。
字符串常量池(StringTable)为什么要做调整呢?

在JDK7中,StringTable就被放在了堆里了。这是因为永久代的回收效率很低,在full gc的时候才会触发。而full gc是因老年代空间不足、永久代不足时才会触发。这就会导致StringTable的效率不高。而正常开发来说,字符串会大量的被创建,回收效率低,导致永久代空间不足,但是放到堆里,就能够及时的回收。

方法区的垃圾回收机制

方法区的垃圾回收主要是两部分:常量池中废弃的常量不再使用的类型
先来说说方法区内常量池之中主要存放的两大类常量:字面量和符号引用。字面量比较接近 Java 语言层次的常量概念,如文本字符串、被声明为 final 的常量值等。而符号引用则属于编译原理方面的概念,包括下面三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

方法区的回收内容:

  • HotSpot 虚拟机对常量池的回收策略是很明确的,只要常量池中的常量没有被任何地方引用,就可以被回收。
  • 判定常量是否废弃是简单,但是判断一个类型是否属于“不再被使用的类”那就比较难的了,需要同时满足三个条件:
    • 该类的所有实例都已经被回收,也就是 Java 堆中不存在该类及其任何派生子类的实例。
    • 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如 OSGi、JSP 的重加载等,否则通常很难达成。
    • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
  • Java 虚拟机被允许堆满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是和对象一样,不使用了就必然会回收。是否对类进行回收,HotSpot 虚拟机提供了 -Xnoclassgc 参数进行控制,还可以使用 -verbose:class 以及 -XX:+TraceClassLoading 、-XX:+TraceClassUnLoading 查看类加载和卸载信息。
  • 在大量使用反射、动态代理、CGLib 等 ByteCode 框架、动态生成 JSP 以及 OSGi 这类频繁自定义 ClassLoader 的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。

总结

本次学完,算是把运行时数据区的内容算是弄完了,本章介绍了方法区的概念和其内存结构,详细的说明了里面各记录了什么信息,也通过了jclasslib插件反编译字节码来了解整体的逻辑关系。

👍创作不易,可能有些语言不是很通畅,如有错误请指正,感谢观看!记得点赞哦!👍

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

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

相关文章

杂记 | 使用FRP搭建内网穿透服务(新版toml配置文件,搭配反向代理食用)

文章目录 01 需求与回顾02 下载程序包03 编辑.toml文件3.1 编辑frps.toml3.2 编辑frpc.toml 04 启动服务4.1 启动服务端4.2 启动客户端 05 配置反向代理&#xff08;可选&#xff09;06 windows设置为默认启动&#xff08;可选&#xff09;6.1 创建启动脚本6.2 设置为开机自启 …

【Spring Cloud】声明性REST客户端:Feign

Spring Cloud Feign ——fallback 服务降级 1. Feign 简介2. Feign 的基础使用2.1 普通 HTTP 请求2.2 Feign 远程调用上传文件接口 1. Feign 简介 Feign 是一个声明式的 HTTP 客户端&#xff0c;它简化了编写基于 REST 的服务间通信代码的过程。在 Spring Cloud 中&#xff0c…

你一定要学会的Java语法 -- 【继承】

书接上回&#xff0c;我们已经学完了类和对象&#xff0c;今天内容可能有一点难&#xff0c;相信自己能跨过这道坎。 目录 一. 继承 1.什么是继承 2. 继承的概念 3. 继承的语法 4.父类成员访问 子类和父类成员变量同名 子类和父类成员方法同名 5.super关键字 6.子类构…

POJ 3254 Corn Fields 状态压缩DP(铺砖问题)

一、题目大意 我们要在N * M的田地里种植玉米&#xff0c;有如下限制条件&#xff1a; 1、对已经种植了玉米的位置&#xff0c;它的四个相邻位置都无法继续种植玉米。 2、题目中有说一些块无论如何&#xff0c;都无法种植玉米。 求所有种植玉米的方案数&#xff08;不种植也…

Vector - CANoe - Vector Hardware Manager基础介绍

经常使用CANoe的人都知道&#xff0c;我们之前使用配置VN系列硬件通道的时候使用的是Vector Hardware Config&#xff0c;非常的方便&#xff0c;不过在Vector Driver Setup驱动版本大于22.14后&#xff0c;为了更好的适用车载以太网相关的配置&#xff0c;以及各个配置之间继承…

kubenetes-kubelet组件

一、kubelet架构 每个节点都运行一个kubelet进程&#xff0c;默认监听10250端口&#xff0c;kubelet作用非常重要&#xff0c;是节点的守护神。 接收并执行 master发来的指令。管理Pod及Pod中的容器。每个kubelet进程会在API Server 上注册节点自身信息&#xff0c;定期向mast…

Java学习_对象

对象在计算机中的执行原理 类和对象的一些注意事项 this关键字 构造器 构造器是一种特殊的方法 : 特殊之处在于&#xff0c;名字必须与所在类的名字一样&#xff0c;而且不能写返回值类型 封装 封装的设计规范&#xff1a;合理隐藏、合理暴露 实体类 成员变量和局部变量的区别 …

程序员的护城河:职业发展的关键元素

目录 1. 技术深度与广度 2. 项目经验与实际操作 3. 沟通与团队协作 4. 持续学习与自我更新 5. 社区参与与开源贡献 6. 创新思维与解决问题的能力 7. 职业规划与自我管理 结语 在科技日新月异的今天&#xff0c;程序员的竞争已经不再仅仅依赖于技术水平&#xff0c;而是…

Citespace的使用

CiteSpace CiteSpace的相关介绍运行CiteSpace CiteSpace的相关介绍 CiteSpace作为一款优秀的文献计量学软件&#xff0c;能够将文献之间的关系以科学知识图谱的方式可视化地展现在我们面前。简单来说&#xff0c;面对海量的文献&#xff0c;CiteSpace能够迅速锁定自己需要关注…

使用openvc进行人脸检测:Haar级联分类器

1 人脸检测介绍 1.1 什么是人脸检测 人脸检测的目标是确定图像或视频中是否存在人脸。如果存在多个面&#xff0c;则每个面都被一个边界框包围&#xff0c;因此我们知道这些面的位置 人脸检测算法的主要目标是准确有效地确定图像或视频中人脸的存在和位置。这些算法分析数据…

如何从零开始手写一个消息中间件(从宏观角度理解消息中间件的技术原理)

如何从零开始手写一个消息中间件&#xff08;从宏观角度理解消息中间件的技术原理&#xff09; 什么是消息中间件消息中间件的作用逐一拆解消息中间件的核心技术消息中间件核心技术总览IOBIONIOIO多路复用AIOIO多路复用详细分析selectpollepoll Java中的IO多路复用 协议序列化消…

阿里云严重故障,影响阿里系、淘宝、饿了么、语雀等都崩了...

作者&#xff1a;JavaPub 编程学习一条龙&#xff1a;http://luxian.javapub.net.cn 就在一年一度的双十一剁手节火热进行时&#xff0c;阿里云服务出现了严重故障。 关键是前不久刚发生了语雀事件&#xff0c;不了解的朋友阅读这里 阿里语雀突发P0级事故&#xff0c;一度崩溃…

ASP.NETWeb开发(C#版)-day1-C#基础+实操

目录 .NET实操&#xff1a;创建项目执行 C#基础语法数据类型变量实操001_变量如何在一个解决方案 中创建另一个项目实操002结构实操003-if else实操004-多分支多行注释按钮实操&#xff1a;循环 面向对象基础如何在同一个项目下创建新的.cs文件实操-类的定义与访问实操-练习实操…

基于springboot实现驾校管理系统项目【项目源码】

基于springboot实现驾校管理系统演示 JAVA简介 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&#xff0…

加班把数据库重构完毕

加班把数据库重构完毕 本文的数据库重构是基于 clickhouse 时序非关系型的数据库。该数据库适合存储股票数据&#xff0c;速度快&#xff0c;一般查询都是 ms 级别&#xff0c;不需要异步查询更新界面 ui。 达到目标效果&#xff1a;数据表随便删除&#xff0c;重新拉数据以及指…

基于C#+WPF编写的调用讯飞星火大模型工具

工具源码&#xff1a;https://github.com/lishuangquan1987/XFYun.SparkChat 工具效果截图&#xff1a; 支持流式输出: 其中ApiKey/ApiSecret/AppId需要自己到讯飞星火大模型官网去注册账号申请&#xff0c;免费的。 申请地址&#xff1a;https://xinghuo.xfyun.cn/ 注册之…

NetSuite 固定资产报表自定义原理及应用

NetSuite固定资产模块一直处于功能迭代更新中&#xff0c;目前23.2的版本能够支持报表的局部自定义&#xff0c;比如增加原值或已折旧期间&#xff0c;甚至固定资产自定义字段等。但是当我们在实际项目中&#xff0c;会遇到一些挑战&#xff0c;例如&#xff1a; 固定资产原值…

Java Web——前端HTML入门

目录 HTML&CSS3&JavaScript简述 1. HTML概念 2. 超文本 3. 标记语言 4. HTML基础结构 5. HTML基础词汇 6. HTML语法规则 7. VS Code 推荐使用的插件 8. 在线帮助文档 HTML&CSS3&JavaScript简述 HTML 主要用于网页主体结构的搭建&#xff0c;像一个毛坯…

【FAQ】Gradle开发问题汇总

1. buildSrc依赖Spring Denpendency时报错 来自预编译脚本的插件请求不能包含版本号。请从有问题的请求中删除该版本&#xff0c;并确保包含所请求插件io.spring.dependency-management的模块是一个实现依赖项 解决方案 https://www.5axxw.com/questions/content/uqw0grhttps:/…

怎么做到高性能网络IO?

为什么要做高性能网络IO。主要是解决c10&#xff0c;c10M问题 最开始的时候我们走的内核协议栈&#xff0c;走内核协议栈其实性能比较低&#xff0c;因为我们之前介绍的时候需要拷贝两次 但是我们采用用户态协议栈可以少拷贝一次&#xff0c;可以大大提高效率&#xff0c; 步骤…