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

寻觅·方法区的内容

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

在这里插入图片描述

文章目录

  • 寻觅·方法区的内容
    • 堆、栈、方法区的交互关系
    • 方法区的概念
      • 了解方法区
      • 设置方法区大小
        • 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: ()Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=10: iconst_01: istore_12: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;5: iload_16: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V9: returnLineNumberTable:line 20: 0line 21: 2line 22: 9LocalVariableTable:Start  Length  Slot  Name   Signature0      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.rhkb.cn/news/189572.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个java文件的JVM之旅

准备 我是小C同学编写得一个java文件&#xff0c;如何实现我的功能呢&#xff1f;需要去JVM(Java Virtual Machine)这个地方旅行。 变身 我高高兴兴的来到JVM&#xff0c;想要开始JVM之旅&#xff0c;它确说&#xff1a;“现在的我还不能进去&#xff0c;需要做一次转换&#x…

解析Python的深浅拷贝机制

引言 在Python编程中&#xff0c;我们经常会遇到数据复制的问题。有时候&#xff0c;我们只是需要复制一份数据的引用&#xff0c;有时候&#xff0c;我们则需要复制数据本身。这就涉及到了Python中的深浅拷贝问题。深浅拷贝是Python中的一个重要概念&#xff0c;理解它对于编…

微软和Red Hat合体:帮助企业更方便部署容器

早在2015年&#xff0c;微软就已经和Red Hat达成合作共同为企业市场开发基于云端的解决方案。时隔两年双方在企业市场的多个方面开展更紧密的合作&#xff0c;今天两家公司再次宣布帮助企业更方便地部署容器。 双方所开展的合作包括在微软Azure上部署Red Hat OpenShift&#xf…

Pyside6/PYQT6如何实现无边框设计,解决无边框窗口无法移动的问题

文章目录 💢 问题 💢💯 解决方案 💯🍔 准备工作🐾 操作步骤🐾 窗口无边框🐾 窗口透明🐾 实现窗口可移动⚓️ 相关链接 ⚓️💢 问题 💢 有时候我们需要一个无边框的UI设计来实现/美化一些功能,如:制作一个桌面时钟,进度条展示等,要实现无边框其实很简…

从开源项目聊鱼眼相机的“360全景拼接”

目录 概述 从360全景的背景讲起 跨过参数标定聊透视变化 拼接图片后处理 参考文献 概述 写这篇文章的原因完全源于开源项目(GitHub参阅参考文献1)。该项目涵盖了环视系统的较为全貌的制作过程&#xff0c;包含完整的标定、投影、拼接和实时运行流程。该篇文章主要是梳理全…

机器学习数据预处理——Word2Vec的使用

引言&#xff1a; Word2Vec 是一种强大的词向量表示方法&#xff0c;通常通过训练神经网络来学习词汇中的词语嵌入。它可以捕捉词语之间的语义关系&#xff0c;对于许多自然语言处理任务&#xff0c;包括情感分析&#xff0c;都表现出色。 代码&#xff1a; 重点代码&#…

科技改变农业:合成数据农业中的应用

介绍 农业在我们的生活中起着至关重要的作用&#xff0c;它为我们提供了生存的食物。如今&#xff0c;它遇到了各种困难&#xff0c;例如气候变化的影响、缺乏工人以及全球流行病造成的中断。这些困难影响了耕作用水和土地的供应&#xff0c;而这些水和土地正变得越来越稀缺。…

PROFINET和UDP、MODBUS-RTU通信速度对比实验

这篇博客我们介绍PROFINET 和MODBUS-RTU通信实验时的数据刷新速度,以及这种速度不同对控制系统带来的挑战都有哪些,在介绍这篇对比实验之前大家可以参考下面的文章链接: S7-1200PLC和SMART PLC的PN智能从站通信 S7-200 SMART 和 S7-1200PLC进行PROFINET IO通信-CSDN博客文…

Adobe Photoshop 2020给证件照换底

1.导入图片 2.用魔法棒点击图片 3.点选择&#xff0c;反选 4.选择&#xff0c;选择并遮住 5.用画笔修饰证件照边缘 6. 7.更换要换的底的颜色 8.新建图层 9.使用快捷键altdelete键填充颜色。 10.移动图层&#xff0c;完成换底。

计算机中丢失msvcr120.dll文件怎么修复?找不到msvcr120.dll五种完美修复方案

今天我想和大家分享的是关于“msvcr120.dll丢失的问题的5个解决方法”。在我们日常的工作生活中&#xff0c;或许大家都曾遇到过这样的问题&#xff0c;那么&#xff0c;了解它的解决方法是非常必要的。 首先&#xff0c;让我们来了解一下msvcr120.dll是什么文件。简单来说&am…

基于springboot实现桥牌计分管理系统项目【项目源码】

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

单链表按位序与指定结点 删除

按位序删除(带头结点) #define NULL 0 #include<stdlib.h>typedef struct LNode {int data;struct LNode* next; }LNode, * LinkList;//按位序删除&#xff08;带头结点&#xff09; bool ListInsert(LinkList& L, int i, int& e) {if (i < 1)return false;L…

js运算,笔试踩坑知识点

文章目录 前端面试系列运算符记住口诀先计算 后 赋值赋值从右向左 和 - -计算从左向右括号里的加减优先于括号外的乘除交换俩数的值答案 前端面试系列 js运算 笔试踩坑知识点 前端js面试题 &#xff08;三&#xff09; 前端js面试题&#xff08;二&#xff09; 前端js面试题 (…

基于SpringBoot的SSMP整合案例(开启日志与分页查询条件查询功能实现)

开启事务 导入Mybatis-Plus框架后&#xff0c;我们可以使用Mybatis-Plus自带的事务&#xff0c;只需要在配置文件中配置即可 使用配置方式开启日志&#xff0c;设置日志输出方式为标准输出mybatis-plus:global-config:db-config:table-prefix: tb_id-type: autoconfiguration:…

【原创课设】java+swing+mysql选课管理系统设计与实现

摘要&#xff1a; 随着学校规模的扩大和课程设置的多样化&#xff0c;传统的手工选课管理方式已经无法满足现代教育的需求。因此&#xff0c;开发一款高效、便捷的选课管理系统变得尤为重要。该系统可以提高选课工作的效率&#xff0c;减少人为错误&#xff0c;同时也能为学生…

工业摄像机参数计算

在工业相机选型的时候有点懵&#xff0c;有一些参数都不知道咋计算的。有些概念也没有区分清楚。‘’ 靶面尺寸 CMOS 或者是 CCD 使用几分之几英寸来标注的时候&#xff0c;这个几分之几英寸计算的是什么尺寸&#xff1f; 一开始我以为这个计算的就是靶面的实际对角线的尺寸…

nfs配置

1.NFS介绍 NFS就是Network File System的缩写&#xff0c;它最大的功能就是可以通过网络&#xff0c;让不同的机器、不同的操 作系统可以共享彼此的文件。 NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文 件系统中&#xff0c;而在本地端的系统中来看&#…

【STM32】TIM2的PWM:脉冲宽度调制--标准库

注意点&#xff1a; TIM_Period---->指要进行比较的值Compare TIM_Prescaler----> 指要进行分频的值【分频值/原始时钟值】 PWM是一种周期固定&#xff0c;脉宽可调整的输出波形。 https://www.cnblogs.com/brianblog/p/7117896.html 0.通用寄存器输出 1.捕获/比较通道…

Docker从零开始学习,及常用命令大全(附带代码讲解)

Docker从零开始&#xff0c;及常用命令大全&#xff08;附带代码讲解&#xff09; docker是一种开源的应用容器引擎&#xff0c;可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。…

Qt QtCreator调试Qt源码配置

目录 前言1、编译debug版Qt2、QtCreator配置3、调试测试4、总结 前言 本篇主要介绍了在麒麟V10系统下&#xff0c;如何编译debug版qt&#xff0c;并通过配置QtCreator实现调试Qt源码的目的。通过调试源码&#xff0c;我们可以对Qt框架的运行机制进一步深入了解&#xff0c;同时…