当前位置: 首页 > news >正文

JVM虚拟机篇(二):深入剖析Java与元空间(MetaSpace)

这里写目录标题

  • JVM虚拟机篇(二):深入剖析Java与元空间(MetaSpace)
    • 一、引言
    • 二、全面认识Java
      • 2.1 Java的起源与发展历程
      • 2.2 Java的特性
        • 2.2.1 简单性
        • 2.2.2 面向对象
        • 2.2.3 平台无关性
        • 2.2.4 健壮性
        • 2.2.5 安全性
        • 2.2.6 多线程
      • 2.3 Java的应用领域
        • 2.3.1 企业级应用开发
        • 2.3.2 安卓应用开发
        • 2.3.3 大数据处理
        • 2.3.4 分布式系统开发
        • 2.3.5 游戏开发
    • 三、元空间(MetaSpace)详解
      • 3.1 元空间的诞生背景
      • 3.2 元空间的工作原理
        • 3.2.1 内存分配
        • 3.2.2 类元数据存储
        • 3.2.3 垃圾回收
      • 3.3 可达性分析
      • 3.4 垃圾回收算法
        • 3.4.1 标记 - 清除算法(Mark - Sweep Algorithm)
        • 3.4.2 复制算法(Copying Algorithm)
        • 3.4.3 标记 - 整理算法(Mark - Compact Algorithm)
        • 3.4.4 分代收集算法(Generational Collection Algorithm)
      • 3.5 元空间相关参数配置
      • 3.6 元空间对Java应用的影响
        • 3.6.1 性能提升
        • 3.6.2 内存管理优化
        • 3.6.3 应用迁移与兼容性
    • 四、总结

JVM虚拟机篇(二):深入剖析Java与元空间(MetaSpace)

一、引言

Java,作为一门广泛应用的编程语言,自诞生以来就凭借其“一次编写,到处运行”的特性、丰富的类库以及强大的生态系统,在软件开发领域占据着重要地位。而元空间(MetaSpace),作为Java虚拟机(JVM)在Java 8及之后版本中的一个重要概念,对Java程序的内存管理和性能有着深远影响。深入了解Java的全貌以及元空间的原理和应用,对于Java开发者来说,不仅有助于编写出高效、稳定的代码,还能在面对复杂问题时,从底层原理出发进行深入分析和解决。接下来,我们将详细地介绍Java以及元空间。

二、全面认识Java

2.1 Java的起源与发展历程

Java语言是由Sun Microsystems公司(现已被Oracle收购)的詹姆斯·高斯林(James Gosling)等人于1991年开始开发的,最初的项目代号为“Green Project” ,旨在为智能家电等小型设备开发一种分布式代码系统。1995年,Java语言正式对外发布,凭借其简单性、面向对象、平台无关性等特性,迅速引起了业界的广泛关注。

在发展过程中,Java经历了多个重要版本的迭代:

  • Java 1.0:1996年发布,标志着Java语言的正式诞生。它引入了基本的Java类库和虚拟机规范,奠定了Java发展的基础。
  • Java 1.2:1998年发布,也被称为Java 2。这个版本对Java进行了重大改进,引入了Java Foundation Classes(JFC),包括Swing图形用户界面工具包等,极大地增强了Java在桌面应用开发方面的能力。同时,它还对Java虚拟机进行了优化,提高了性能。
  • Java 5.0:2004年发布,引入了许多重要的新特性,如泛型(Generics)、自动装箱/拆箱(Autoboxing/Unboxing)、增强型for循环(for - each loop)、枚举类型(Enumerations)等。这些特性使得Java代码更加简洁、安全和易于编写,推动了Java在企业级开发等领域的广泛应用。
  • Java 8:2014年发布,是Java发展历程中的一个重要里程碑。它引入了函数式编程特性(如Lambda表达式、方法引用等),对Java集合框架进行了增强,同时还改进了日期和时间API等。此外,Java 8在虚拟机层面引入了元空间(MetaSpace)来替代永久代(PermGen),对内存管理进行了优化。
  • Java 11:2018年发布,是一个长期支持(LTS)版本。它引入了局部变量类型推断(var关键字)、HTTP客户端API等新特性,并且对Java虚拟机进行了进一步的性能优化和增强。

2.2 Java的特性

2.2.1 简单性

Java的语法相对简洁明了,它去除了C++中一些复杂且容易出错的特性,如指针操作、多重继承等。例如,Java使用自动的内存管理机制(垃圾回收),开发者无需手动释放内存,减少了内存泄漏和悬空指针等问题的发生。同时,Java的语法结构类似于C和C++,对于有一定编程基础的开发者来说容易上手。

2.2.2 面向对象

Java是一门纯粹的面向对象编程语言。它支持面向对象的基本概念,如类、对象、继承、封装和多态。通过类和对象,开发者可以将现实世界中的事物抽象为程序中的实体,方便进行代码的组织和管理。继承机制允许子类继承父类的属性和方法,实现代码的复用;封装可以将数据和操作数据的方法封装在一起,隐藏内部实现细节,提高代码的安全性和可维护性;多态则使得不同类型的对象可以对同一消息作出不同的响应,增加了程序的灵活性。

2.2.3 平台无关性

这是Java最为突出的特性之一。Java程序通过编译器将源文件(.java)编译成字节码文件(.class),字节码是一种与平台无关的中间代码。然后,不同操作系统和硬件平台上的Java虚拟机(JVM)可以执行这些字节码。无论是在Windows、Linux还是Mac OS等操作系统上,只要安装了相应的JVM,Java程序都可以运行,真正实现了“一次编写,到处运行”。

2.2.4 健壮性

Java具有较强的健壮性。它的强类型检查机制在编译和运行时都会对数据类型进行严格检查,避免了许多因类型不匹配而导致的错误。同时,Java的异常处理机制允许开发者捕获和处理程序运行过程中出现的异常情况,使得程序在面对错误时能够更加优雅地处理,而不是崩溃。此外,Java的自动垃圾回收机制也有助于保持程序的稳定性,自动回收不再使用的内存,减少了因内存管理不当而引发的问题。

2.2.5 安全性

Java在设计上考虑了多方面的安全性。它的字节码验证机制会在类加载时对字节码进行验证,确保字节码符合JVM的规范,不会对系统造成安全威胁。Java的沙箱模型(Sandbox Model)限制了Java程序对系统资源的访问,在未授予足够权限的情况下,Java程序不能随意访问本地文件系统、网络资源等,提高了程序运行的安全性。此外,Java还支持数字签名等安全技术,用于验证代码的来源和完整性。

2.2.6 多线程

Java内置了对多线程的支持。通过java.lang.Thread类以及相关的API,开发者可以方便地创建和管理线程,实现多线程编程。多线程使得Java程序可以同时执行多个任务,提高了程序的执行效率和响应能力。例如,在一个图形用户界面应用中,一个线程可以用于处理用户界面的交互,另一个线程可以用于执行耗时的计算任务,避免了界面的卡顿。

2.3 Java的应用领域

2.3.1 企业级应用开发

Java在企业级应用开发领域占据着主导地位。许多大型企业级应用,如企业资源规划(ERP)系统、客户关系管理(CRM)系统、供应链管理(SCM)系统等,都是用Java开发的。Java的企业级框架,如Spring、Spring Boot、Spring Cloud、Hibernate等,提供了丰富的功能和工具,帮助开发者快速构建高效、可扩展、安全的企业级应用。这些框架涵盖了从依赖注入、面向切面编程到数据库访问、分布式系统开发等多个方面,极大地提高了开发效率。

2.3.2 安卓应用开发

安卓操作系统的应用开发主要使用Java语言(虽然现在也支持Kotlin等语言,但Java仍然占据重要地位)。安卓开发中,开发者使用Java来编写安卓应用的业务逻辑、界面交互等。安卓提供了丰富的Java API,用于创建用户界面、访问设备资源(如摄像头、传感器等)、进行网络通信等。众多知名的安卓应用,如微信、支付宝等,都有大量的Java代码。

2.3.3 大数据处理

在大数据领域,Java也有着广泛的应用。许多大数据处理框架,如Hadoop、Spark等,都是用Java编写的或者提供了对Java的支持。Hadoop是一个分布式存储和计算框架,用于处理大规模数据集,它的核心组件如HDFS(分布式文件系统)和MapReduce(分布式计算模型)都是用Java实现的。Spark是一个快速、通用的大数据处理引擎,它提供了Java API,方便Java开发者进行大数据处理和分析。

2.3.4 分布式系统开发

Java具备开发分布式系统的强大能力。通过Java的RMI(远程方法调用)、EJB(企业级JavaBean)等技术,以及现代的分布式框架如Spring Cloud等,开发者可以构建分布式应用程序。这些应用程序可以分布在多个服务器节点上,实现负载均衡、高可用性和可扩展性。例如,许多电商平台、金融系统等都采用了基于Java的分布式架构。

2.3.5 游戏开发

虽然Java在游戏开发领域不如C++等语言那么普遍,但也有一定的应用。Java的图形库,如JavaFX、Swing等,可以用于开发2D游戏界面。同时,一些开源的游戏引擎,如LibGDX,也支持用Java进行游戏开发。此外,在一些网页游戏和移动游戏的后端开发中,Java也经常被使用,用于处理游戏逻辑、用户数据存储和管理等。

三、元空间(MetaSpace)详解

3.1 元空间的诞生背景

在Java 8之前,JVM中的方法区是通过永久代(PermGen)来实现的。永久代用于存储类的元数据(如类的结构信息、常量池、静态变量等)、即时编译器编译后的代码缓存等内容。然而,永久代存在一些问题:

  • 内存大小限制:永久代的大小是通过-XX:MaxPermSize参数来设置的,在实际应用中,很难准确地预估永久代所需的内存大小。如果设置过小,可能会导致java.lang.OutOfMemoryError: PermGen space错误,使得应用程序崩溃;如果设置过大,又会浪费系统内存资源。
  • 类加载回收困难:随着应用程序的运行,类的加载和卸载频繁发生。在永久代中,对类元数据的回收比较困难,容易导致内存泄漏等问题。尤其是在一些动态加载类比较多的应用场景中,如使用大量反射、动态代理等技术的应用,永久代的内存管理问题更加突出。

为了解决这些问题,从Java 8开始,JVM引入了元空间(MetaSpace)来替代永久代。元空间使用本地内存(Native Memory),而不是像永久代那样在JVM堆内存中划分一块区域。这使得元空间的大小不再受限于-XX:MaxPermSize参数,而是仅受限于系统的可用内存,从而在很大程度上缓解了内存管理方面的压力。

3.2 元空间的工作原理

3.2.1 内存分配

元空间使用本地内存进行类元数据的存储。当JVM加载一个类时,会在元空间中为该类的元数据分配内存。元空间的内存分配由元空间子系统(MetaSpace Subsystem)来管理,它会根据需要向操作系统申请内存。与永久代不同,元空间没有固定的初始大小和最大大小限制(理论上仅受系统可用内存限制),它可以根据类的加载情况动态地扩展和收缩。

3.2.2 类元数据存储

在元空间中,存储的类元数据主要包括以下几个方面:

  • 类的结构信息:如类的名称、父类名称、实现的接口、字段信息、方法信息等。这些信息用于描述类的定义和结构,JVM在执行字节码指令时需要依赖这些信息来进行方法调用、字段访问等操作。
  • 常量池:常量池包含了类中的各种常量,如字符串常量、基本类型常量、类和接口的全限定名、字段和方法的名称及描述符等。常量池在类加载和运行时都起着重要作用,例如在方法调用时,需要通过常量池来解析方法的符号引用。
  • 静态变量:类的静态变量也存储在元空间中。静态变量属于类本身,而不是类的实例,它们在类加载时被分配内存并初始化。
  • 即时编译器编译后的代码缓存:JVM的即时编译器(JIT)会将热点代码编译成机器码,编译后的代码缓存也存储在元空间中。这样在后续执行时可以直接执行编译后的机器码,提高执行效率。
3.2.3 垃圾回收

元空间中的垃圾回收主要是针对不再使用的类元数据进行的。当一个类不再被引用时,它的元数据就成为了垃圾,需要被回收。JVM通过可达性分析来判断类是否仍然被引用。如果一个类的所有实例都已经被回收,并且没有其他地方引用该类(如通过反射等方式),那么这个类就可以被卸载,其在元空间中占用的内存也会被回收。

元空间的垃圾回收与堆内存的垃圾回收是相互配合的。在进行垃圾回收时,JVM会先标记堆中存活的对象,然后根据这些存活对象所引用的类信息,来判断元空间中哪些类元数据仍然是可达的,哪些是可以回收的。元空间的垃圾回收算法主要包括标记 - 清除算法等,通过这些算法来释放不再使用的内存空间。

3.3 可达性分析

垃圾回收的第一步是确定哪些对象是 “垃圾”,即哪些对象不再被程序使用。Java 使用可达性分析算法来实现这一目标。该算法的基本思路是从一系列被称为 “GC Roots” 的对象开始,通过引用关系向下搜索,能够被 GC Roots 直接或间接引用的对象被认为是 “可达” 的,这些对象是存活的,不会被回收;而那些无法被 GC Roots 引用到的对象则被判定为 “不可达”,也就是垃圾对象,会被垃圾回收器回收。

GC Roots 一般包括以下几种对象:

  • 虚拟机栈(栈帧中的局部变量表)中引用的对象:例如,在一个方法中定义的局部变量所引用的对象,只要该方法还在执行,这些对象就是可达的。
  • 方法区中类静态属性引用的对象:类的静态变量所引用的对象,只要类还在加载状态或者没有被卸载,这些对象就是可达的。
  • 方法区中常量引用的对象:方法区常量池中的常量所引用的对象,如字符串常量所引用的String对象等。
  • 本地方法栈中 JNI(Native 方法)引用的对象 :当 Java 程序通过 JNI 调用本地方法时,本地方法中引用的对象也是可达的。

3.4 垃圾回收算法

3.4.1 标记 - 清除算法(Mark - Sweep Algorithm)

这是一种较为基础的垃圾回收算法。其执行过程分为两个阶段:

  • 标记阶段:垃圾回收器从 GC Roots 开始遍历,标记出所有存活的对象。
  • 清除阶段:遍历整个堆内存,将未被标记的对象(即垃圾对象)所占用的内存空间回收。

该算法的优点是实现简单,不需要进行对象的移动。然而,它存在一些明显的缺点:

  • 内存碎片化:在清除垃圾对象后,会产生大量不连续的内存碎片。随着时间的推移,这些碎片会导致在分配较大对象时,即使堆中总的空闲内存足够,但由于没有连续的内存空间,而无法成功分配内存。
  • 效率较低:标记和清除两个阶段都需要遍历整个堆内存,当堆内存较大且对象较多时,执行效率较低。
3.4.2 复制算法(Copying Algorithm)

复制算法将内存空间划分为两块大小相等的区域,每次只使用其中一块。当这一块内存空间用完后,就将存活的对象复制到另一块未使用的区域中,然后将原来使用的区域一次性全部清理掉。

该算法的优点是:

  • 执行效率高:只需要复制存活的对象,并且清理操作简单,没有标记 - 清除算法中的碎片化问题。
  • 实现相对简单:相比于其他一些复杂的算法,复制算法的实现逻辑较为清晰。

但它也有缺点:

  • 内存利用率低:由于始终只有一半的内存空间在使用,对于内存资源有限的系统来说,这是一个较大的浪费。
3.4.3 标记 - 整理算法(Mark - Compact Algorithm)

标记 - 整理算法结合了标记 - 清除算法和复制算法的优点。它首先进行标记阶段,与标记 - 清除算法一样,从 GC Roots 开始标记存活的对象。然后,在整理阶段,将存活的对象向一端移动,最后清理掉边界以外的内存空间。

优点:

  • 解决内存碎片化问题:通过移动存活对象,使得内存空间连续,避免了标记 - 清除算法中内存碎片化的问题。
  • 相对较高的内存利用率:不像复制算法那样浪费一半的内存空间。

缺点:

  • 效率相对较低:在整理阶段需要移动对象,并且要更新对象的引用地址,这会带来一定的性能开销。
3.4.4 分代收集算法(Generational Collection Algorithm)

分代收集算法并不是一个全新的算法,而是根据对象的存活周期将堆内存划分为不同的区域,然后针对不同区域采用不同的垃圾回收算法。在 Java 堆中,通常将堆分为新生代和老年代:

  • 新生代:大多数对象在创建后很快就不再使用,因此新生代中的对象存活周期较短。新生代通常采用复制算法进行垃圾回收。它将新生代进一步划分为伊甸园区(Eden Space)和两个幸存区(Survivor 0 Space 和 Survivor 1 Space)。对象首先在伊甸园区分配内存,当伊甸园区满时,触发 Minor GC(新生代垃圾回收),将存活的对象复制到其中一个幸存区。如果幸存区也满了,再次触发 GC 时,存活时间较长的对象会被晋升到老年代。
  • 老年代:老年代中的对象存活周期较长,通常采用标记 - 清除算法或标记 - 整理算法进行垃圾回收。当老年代内存空间不足时,会触发 Full GC(全堆垃圾回收),对整个堆内存进行垃圾回收。

分代收集算法的优点是根据对象的不同特性采用不同的回收算法,提高了垃圾回收的效率,同时也兼顾了内存的合理利用。

3.5 元空间相关参数配置

虽然元空间没有像永久代那样严格的固定大小限制,但JVM仍然提供了一些参数来对元空间进行配置和管理:

  • -XX:MetaspaceSize:这个参数指定了元空间的初始大小。当元空间使用的内存达到这个值时,JVM会触发垃圾回收,尝试回收不再使用的类元数据。如果回收后仍然无法满足需求,元空间会继续扩展。默认情况下,不同的操作系统和JVM版本可能会有不同的初始值。
  • -XX:MaxMetaspaceSize:该参数用于设置元空间的最大大小。虽然元空间理论上仅受系统可用内存限制,但通过这个参数可以限制元空间使用的最大内存量,以防止元空间过度占用系统内存。如果元空间使用的内存达到这个最大值,并且仍然无法满足类加载等需求,JVM会抛出java.lang.OutOfMemoryError: Metaspace错误。
  • -XX:MinMetaspaceFreeRatio-XX:MaxMetaspaceFreeRatio:这两个参数分别指定了元空间在进行垃圾回收后,空闲内存占总元空间大小的最小比例和最大比例。当元空间的空闲内存比例低于MinMetaspaceFreeRatio时,JVM会尝试进行垃圾回收以释放更多内存;当空闲内存比例高于MaxMetaspaceFreeRatio时,JVM可能会收缩元空间的大小,减少其所占用的内存。

3.6 元空间对Java应用的影响

3.6.1 性能提升

元空间的引入在一定程度上提高了Java应用的性能。由于元空间使用本地内存,避免了像永久代那样在堆内存中频繁分配和回收内存所带来的开销。同时,元空间的动态扩展和收缩机制使得内存管理更加灵活,能够更好地适应类加载的动态变化。在一些动态加载类较多的应用场景中,如使用框架进行动态代理、反射等操作的应用,元空间的性能优势更加明显,减少了因类元数据管理不当而导致的性能瓶颈。

3.6.2 内存管理优化

元空间解决了永久代在内存管理方面的一些难题。不再受限于固定的-XX:MaxPermSize参数,使得开发者在配置JVM内存时更加轻松,减少了因永久代大小设置不合理而导致的内存溢出问题。同时,元空间的垃圾回收机制更加高效,能够更好地处理类元数据的回收,降低了内存泄漏的风险。

3.6.3 应用迁移与兼容性

对于从Java 7及之前版本迁移到Java 8及之后版本的应用程序,需要注意元空间带来的变化。由于元空间替代了永久代,一些与永久代相关的参数配置(如-XX:MaxPermSize)在Java 8及之后版本中不再适用,需要进行相应的调整。此外,在一些依赖于永久代特性的应用中,可能需要进行代码修改和优化,以确保在元空间环境下能够正常运行。例如,一些通过反射获取类元数据并进行特殊处理的代码,可能需要重新检查和调整,以适应元空间的内存管理和类元数据存储方式。

四、总结

Java作为一门功能强大、应用广泛的编程语言,凭借其众多优秀的特性,在软件开发的各个领域都发挥着重要作用。从企业级应用到安卓开发,从大数据处理到分布式系统构建,Java都有着深厚的应用基础和丰富的生态支持。

而元空间作为Java 8及之后版本中JVM内存管理的重要改进,解决了永久代存在的诸多问题,提高了Java应用的性能和内存管理效率。深入了解Java的全貌以及元空间的原理和应用,对于Java开发者来说是不断提升技术水平、应对复杂开发场景的关键。在未来的Java开发中,随着技术的不断发展和演进,我们需要持续关注Java语言和JVM的新特性,不断学习和探索,以编写出更加高效、稳定、安全的Java程序。

希望通过本文的介绍,读者能够对Java和元空间有一个全面、深入的认识,并在实际的开发工作中更好地应用这些知识。

相关文章:

JVM虚拟机篇(二):深入剖析Java与元空间(MetaSpace)

这里写目录标题 JVM虚拟机篇(二):深入剖析Java与元空间(MetaSpace)一、引言二、全面认识Java2.1 Java的起源与发展历程2.2 Java的特性2.2.1 简单性2.2.2 面向对象2.2.3 平台无关性2.2.4 健壮性2.2.5 安全性2.2.6 多线程…...

NDK开发:音视频处理基础

音视频处理基础 一、音视频基础 1.1 音视频基本概念 视频编码格式 H.264/AVCH.265/HEVCVP8/VP9AV1音频编码格式 AACMP3PCMOPUS封装格式 MP4FLVMKVTS1.2 音视频处理流程 视频处理流程 采集(Camera/Screen)预处理(美颜/滤镜)编码(H.264/H.265)封装传输/存储音频处理流程 …...

【数字电路】第一章 数制和码制

一、数码的基本概念 1.数制 2.码制 二、几种常用的数制 三、不同数制间的转换 八进制和十六进制间通常不直接进行转换,而是先转换成二进制或十进制然后再进行转换。 1.任意进制→十进制(N—十转换) 2.十进制→任意进制(十—N转换…...

软件工程面试题(二十九)

1、Internet的最顶级的商业域名叫什么? 答: .com 2、GC是什么,为什么要使用它? 垃圾回收 (garbage collection, GC) 一个跟踪过程,它传递性地跟踪指向当前使用的对象的所有指针,以便找到可以引用的所有对象,然后重新使用在此跟踪过程中未找到的任何堆内存。公共语言运行…...

6.第二阶段x64游戏实战-分析人物状态

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:5.第二阶段x64游戏实战-动态模块地址 人物状态是与角色相关的,如果…...

Synopsys:设计对象

相关阅读 Synopsyshttps://blog.csdn.net/weixin_45791458/category_12812219.html?spm1001.2014.3001.5482 对于Synopsys的EDA工具(如Design Compiler、PrimeTime、IC Compiler)等,设计对象(Design Objects)是组成整个设计的抽象表示&…...

Redis数据结构之Hash

目录 1.概述2.常见操作2.1 H(M)SET/H(M)GET2.2 HGETALL2.3 HDEL2.4 HLEN2.5 HEXISTS2.6 HKEYS/HVALS2.7 HINCRBY2.8 HSETNX 3.总结 1.概述 Hash是一个String类型的field(字段)和value(值)的映射表&#xff0c;而且value是一个键值对集合&#xff0c;类似Map<String, Map<…...

【VUE】RuoYi-Vue3项目结构的分析

【VUE】RuoYi-Vue3项目结构的分析 1. 项目地址2. RuoYi-Vue3项目结构2.1 整体结构2.2 package.json2.2.1 &#x1f9fe; 基本信息2.2.2 &#x1f527; 脚本命令&#xff08;scripts&#xff09;2.2.3 &#x1f30d; 仓库信息2.2.4 &#x1f4e6; 项目依赖&#xff08;dependenc…...

libreoffice-help-common` 的版本(`24.8.5`)与官方源要求的版本(`24.2.7`)不一致

出现此错误的原因主要是软件包依赖冲突&#xff0c;具体分析如下&#xff1a; ### 主要原因 1. **软件源版本不匹配&#xff08;国内和官方服务器版本有差距&#xff09; 系统中可能启用了第三方软件源&#xff08;如 PPA 或 backports 源&#xff09;&#xff0c;导致 lib…...

5.数据手册解读——共模电感

目录 1 共模电感的工作原理 2 核心参数解读 2.1 电气参数 2.2 阻抗特性 共模电感(Common mode Choke)&#xff0c;也叫共模扼流圈&#xff0c;是在一个闭合磁环上对称绕制方向相反、匝数相同的线圈。理想的共模扼流圈对L&#xff08;或N&#xff09;与E之间的共模干扰具有抑…...

easy-poi 一对多导出

1. 需求&#xff1a; 某一列上下两行单元格A,B值一样且这两个单元格&#xff0c; 前面所有列对应单元格值一样的话&#xff0c; 就对A,B 两个单元格进行纵向合并单元格 1. 核心思路&#xff1a; 先对数据集的国家&#xff0c;省份&#xff0c;城市...... id 身份证进行排序…...

用C语言控制键盘上的方向键

各位同学&#xff0c;大家好&#xff01;相信大家在学习C语言的过程中&#xff0c;都和我一样&#xff0c;经常使用scanf函数来接受字符&#xff0c;数字&#xff0c;这些标准输入信息&#xff0c;来实现自己设计的程序效果。 而我突然有一天&#xff08;对就是今天&#xff09…...

第3课:状态管理与事件处理

第3课&#xff1a;状态管理与事件处理 学习目标 掌握useState Hook的使用理解组件事件处理机制实现表单输入与状态绑定完成任务添加功能原型 一、useState基础 1. 创建第一个状态 新建src/Counter.js&#xff1a; import { useState } from react;function Counter() {co…...

硬件工程师面试问题(五):蓝牙面试问题与详解

蓝牙技术作为物联网与智能设备的核心无线协议&#xff0c;其硬件设计能力直接影响产品连接稳定性、功耗及兼容性。面试是评估候选人射频电路设计、天线优化、协议栈调试等综合技能的关键环节&#xff0c;尤其在BLE低功耗设计、共存抗干扰等场景中&#xff0c;硬件工程师的实践经…...

leetcode4.寻找两个正序数组中的中位数

思路源于 LeetCode004-两个有序数组的中位数-最优算法代码讲解 基本思路是将两个数组看成一个数组&#xff0c;然后划分为两个部分&#xff0c;若为奇数左边部分个数多1&#xff0c;若为偶数左边部分等于右边部分个数。i表示数组1划分位置&#xff08;i为4是索引4也表示i的左半…...

20250405在荣品的PRO-RK3566开发板使用Rockchip原厂的buildroot系统来适配gmac1

【暂时还没有解决让PRO-RK3566的eth0/gmac1开机就启动】 PRO-RK3566作为iperf服务器&#xff1a; rootrk3566-buildroot:/# ifconfig rootrk3566-buildroot:/# ifconfig -a rootrk3566-buildroot:/# ifconfig eth0 up rootrk3566-buildroot:/# ifconfig rootrk3566-buildroot:/…...

7. 记忆(Memory)机制:让AI拥有“短期记忆”与“长期记忆”

引言&#xff1a;当AI学会"记住你" 2025年某银行智能客服因无法记住用户身份&#xff0c;每次对话都要求重复验证&#xff0c;引发大量投诉。引入LangChain 记忆系统后&#xff0c;客户满意度提升62%。本文将基于MemorySaver与FAISS本地存储&#xff0c;教你构建符合…...

Chapter07_图像压缩编码

文章目录 图像压缩编码图像压缩编码基础图像压缩的基本概念信息相关信息冗余信源编码及其分类 图像编码模型信源编码器模型信源解码器模型 数字图像的信息熵信源符号码字平均长度信息熵信息量 变长编码费诺码霍夫曼编码 位平面编码格雷码 图像压缩编码 数字图像的压缩是指在满…...

网络安全之前端学习(css终章)

如大家所见&#xff0c;今天的文章就是css的最后一篇文章。那么话不多说&#xff0c;我们开始吧。本章内容比较杂&#xff0c;就是补充之前几章没讲到的。 关系选择器 之前我们讲到了很多选择器&#xff0c;这里补充一个关系选择器。 1.1后代选择器 后代选择器&#xff0c;…...

多线程代码案例 - 2

阻塞队列 阻塞队列&#xff0c;我们熟悉的概念是队列&#xff0c;即一种先进先出的数据结构。阻塞队列&#xff0c;就是基于普通队列做出的扩展。 特点 1. 线程安全的 2. 具有阻塞特性 &#xff08;a&#xff09;如果针对一个已经满了的队列进行入队列&#xff0c;此时入队操…...

Qt实现鼠标右键弹出弹窗退出

Qt鼠标右键弹出弹窗退出 1、鼠标右键实现1.1 重写鼠标点击事件1.2 添加头文件1.3 添加定义2、添加菜单2.1添加菜单头文件2.2创建菜单对象2.3 显示菜单 3、添加动作3.1添加动作资源文件3.2 添加头文件3.3 创建退出动作对象3.4菜单添加动作对象 4、在当前鼠标位置显示菜单4.1当前…...

AI绘画中的LoRa是什么?

Lora是一个多义词&#xff0c;根据不同的上下文可以指代多种事物。以下将详细介绍几种主要的含义&#xff1a; LoRa技术 LoRa&#xff08;Long Range Radio&#xff09;是一种低功耗广域网&#xff08;LPWAN&#xff09;无线通信技术&#xff0c;以其远距离、低功耗和低成本的特…...

LaTeX、KaTeX、Markdown 的用法

文章目录 1. LaTeX 用法概述1.1 LaTeX简介1.2 优点与应用场景2. LaTeX 基础语法2.1 文档结构2.2 文本格式化2.3 数学公式3. KaTeX 用法3.1 KaTeX简介3.2 基本使用方法3.2.1 引入KaTeX3.2.2 渲染数学公式3.2.3 自定义配置3.3 与LaTeX的兼容性4. Markdown 用法4.1 Markdown简介4.…...

Python 如何高效实现 PDF 内容差异对比

Python 如何高效实现 PDF 内容差异对比 1. 安装 PyMuPDF 库2. 获取 PDF 内容通过文件路径获取通过 URL 获取 3. 提取 PDF 每页信息4. 内容对比metadata 差异文本对比可视化对比 5. 提升对比效率通过哈希值快速判断页面是否相同早停机制多进程机制 6. 其他 最近有接触到 PDF 内容…...

JJJ:generic netlink例程分析

接嵌入式毕设、课设辅导、技术咨询&#xff0c;欢迎私信 完整代码&#xff1a;github代码仓链接 若想要和指定的generic netlink family通信&#xff0c;如: 994 static struct genl_family genl_ctrl __ro_after_init { // generic netlink子协议995 .module THIS_MODU…...

3D图像重建中Bundle Adjustment的推导与实现

介绍 捆集调整(Bundle Adjustment),也称为光束平差法,是一种利用来自多台相机的图像数据同时优化相机位置和姿态以及 3D 点位置的技术。该技术历史相当悠久,于 1958 年由 DC Brown1 首次提出。 最初这是美国空军正在进行的从航拍照片中恢复环境的研究,随着视觉SLAM和Sf…...

【代码模板】C语言如何修改文件权限?读写执行权限对应值是多少?(chmod(“./a.out“, 0741);bit 2 1 0表示 读 写 执行)

#include "stdio.h" #include "unistd.h"int main(int argc, char *argv[]) {if (chmod("./a.out", 0741) ! 0) {perror("Failed to set exec permission");return -1;}return 1; }0741中0是8进制&#xff0c;7是 0111&#xff0c; 4是…...

新版pycharm如何实现debug调试需要参数的python文件

在最顶上有这个选项 把鼠标移上去 点击号 选择python 具体长这样 名字随便取 script选择你要调试的python文件 脚本形参填入参数&#xff0c;如&#xff1a;--arg1 value1 --arg2 value2 点击应用确定 最后给文件打上断点&#xff0c;再点击调试按键&#xff0c;就可以调试了…...

赚钱模拟器-百宝库v0.1.1

#include<bits/stdc.h> #include<windows.h> using namespace std; int n,i,j; void welcome(); void zhuye(); void GAME(); int main(){welcome();zhuye();return 0; }void welcome(){cout<<"欢迎您使用更多资源-百宝库v0.1.1"<<endl;sys…...

实战打靶集锦-38-inclusiveness

文章目录 1. 主机发现2. 端口扫描&服务枚举3. 服务探查4.系统提权 靶机地址&#xff1a;https://download.vulnhub.com/inclusiveness/Inclusiveness.ova 1. 主机发现 目前只知道目标靶机在192.168.56.xx网段&#xff0c;通过如下的命令&#xff0c;看看这个网段上在线的主…...

01人工智能基础入门

一、AI应用场景和发展历程 1.1行业应用 1、deepdream图像生成、yolo目标检测 2、知识图谱、画风迁移 3、语音识别、计算机视觉 4、用户画像 5、百度人工智能布局 1.2发展历程 人工智能的发展经历了 3 个阶段&#xff1a; 1980年代是正式成形期&#xff0c;尚不具备影响力。 …...

SortedSet结构之用户积分实时榜单实战

Redis 中的SortedSet结构非常适合用于实现实时榜单的场景&#xff0c;它根据成员的分数自动进行排序&#xff0c;支持高效的添加、更新和查询操作。 SortedSet实时榜单的一些典型应用场景&#xff1a; 游戏中的玩家排行榜&#xff1a;在多人在线游戏中&#xff0c;使用 Sorte…...

C++_类和对象(上)

【本节目标】 面向过程和面向对象初步认识类的引入类的定义类的访问限定符及封装类的作用域.类的实例化类的对象大小的计算类成员函数的this指针 1. 面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过…...

vllm作为服务启动,无需额外编写sh文件,一步到位【Ubuntu】

看到网上有的vllm写法&#xff0c;需要额外建立一个.sh文件&#xff0c;还是不够简捷。这里提供一种直接编写service文件一步到位的写法&#xff1a; vi /etc/systemd/system/vllm.service [Unit] DescriptionvLLM Service Afternetwork.target[Service] Typesimple Userroot…...

Mathematics | Branch

注&#xff1a;本文为“遇见数学”翻译的 “数学分支概览” 两篇文章合辑。 数学世界的版图&#xff1a;主要分支概览&#xff08;上&#xff09; 原创 遇见数学 2025 年 04 月 03 日 12:02 河南 数学的分支&#xff08;Areas of Mathematics&#xff09; 在文艺复兴之前&am…...

8.5/Q1,Charls最新文章解读

文章题目&#xff1a;Associations of estimated glucose disposal rate with frailty progression: results from two prospective cohorts DOI&#xff1a;10.1186/s12933-025-02650-7 中文标题&#xff1a;估计葡萄糖处理率与虚弱进展的关系&#xff1a;两个前瞻性队列的结果…...

PCL学习(5)随机采样一致性算法RANSAC

一、RANSAC概念及作用 1.1 基本概念 RANSAC是一种鲁棒的参数估计方法&#xff0c;用于从包含大量异常值的数据中拟合数学模型。其核心思想是通过随机采样和迭代验证&#xff0c;找到最优的模型参数&#xff0c;避免异常值的干扰。 1.2 核心思想 随机采样&#xff1a;每次从数…...

app逆向专题一:如何下载app

app逆向专题一&#xff1a;如何下载app 一、打开豌豆荚官网 一、打开豌豆荚官网 打开豌豆荚官网豌豆荚&#xff0c;在右上角搜索框中输入要下载的app名称 依次点击搜索–查看–普通下载&#xff0c;即可将apk文件下载到本地电脑上。...

将 DataFrame 中某一列的列表拆分成多个独立的列的方式

要将 DataFrame 中某一列的列表拆分成多个独立的列&#xff0c;可以使用以下方法&#xff0c;具体取决于数据结构和需求&#xff1a; 场景示例 假设 DataFrame 中 genres 列存储的是列表&#xff08;如 [drama, action]&#xff09;&#xff0c;目标是将每个列表元素拆分成多列…...

VUE+SPRINGBOOT+语音技术实现智能语音歌曲管理系统

语音控制歌曲的播放、暂停、增删改查 <template><div class"Music-container"><div style"margin: 10px 0"><!--检索部分--><el-input style"width: 200px;" placeholder"请输入歌曲名称"v-model"sen…...

安卓开发工程师-自定义 View

1. 如何创建一个简单的自定义 View&#xff1f; 创建自定义 View 的基本步骤如下&#xff1a; 继承 View 或其子类&#xff1a;自定义 View 可以继承自 View 或其他更具体的视图类&#xff08;如 ImageView、Button 等&#xff09;。重写构造方法&#xff1a;通常需要重写三个…...

Vue中权限控制的方案

文章目录 源码&#xff1a;一、页面级1.1、路由守卫1.2、动态路由 二、按钮级别2.1、通过v-if来判断2.2、通过组件包裹的方式来判断2.3、通过自定义指令的方式 三、接口级别 源码&#xff1a; https://gitee.com/liu-qiang-yyds/sysPermission 一、页面级 1.1、路由守卫 前端…...

磁盘分析工具合集:告别C盘焦虑!

今天李师傅带大家盘点五款硬盘空间分析利器&#xff0c;帮你精准定位那些"吃空间"的元凶&#xff0c;让C盘告别臃肿烦恼&#xff01; 一、WizTree 这款NTFS磁盘的"透视眼"堪称效率典范。它通过直接读取硬盘主文件表(MFT)实现秒级扫描&#xff0c;1TB机械…...

硬件学习之器件篇-蜂鸣器

根据工作原理的不同&#xff0c;可以分为电磁式蜂鸣器和压电式蜂鸣器。 1、电磁式蜂鸣器 电磁式蜂鸣器根据内部是否有震荡源&#xff0c;又可以分为有源电磁式蜂鸣器和无源电磁式蜂鸣器。 1.1 外观区别 有源电磁式蜂鸣器从底部看是&#xff0c;是黑胶密封的。 无源电磁式蜂…...

紫檀博物馆一游与软件开发

今天去逛了中国紫檀博物馆&#xff0c;里边很多层展品&#xff0c;也有一些清代的古物&#xff0c;檀木&#xff0c;黄花梨木家具和各种摆件&#xff0c;馆主陈丽华女士也是发心复原、保留和弘扬中国的传统文化&#xff0c;和西游记唐僧扮演者迟成瑞先生一家。 每一件展品都精…...

Cribl 新建Datatype

Cribl 数据dataset 有个很重要的就是datatype, 下面来新建一下: 先看一下原来的datatype : 再点击Add Datatype: Rule...

开源 LLM 应用开发平台 Dify 全栈部署指南(Docker Compose 方案)

开源 LLM 应用开发平台 Dify 全栈部署指南&#xff08;Docker Compose 方案&#xff09; 一、部署环境要求与前置检查 1.1 硬件最低配置 组件要求CPU双核及以上内存4GB 及以上磁盘空间20GB 可用空间 1.2 系统兼容性验证 ✅ 官方支持系统&#xff1a; Ubuntu 20.04/22.04 L…...

医药档案区块链系统

1. 医生用户模块​​ ​​目标用户​​&#xff1a;医护人员 ​​核心功能​​&#xff1a; ​​检索档案​​&#xff1a;通过关键词或筛选条件快速定位患者健康档案。​​请求授权​​&#xff1a;向个人用户发起档案访问权限申请&#xff0c;需经对方确认。​​查看档案​…...

Redis常见命令

(一)常见命令① 一、数据结构 二、通用命令 ①KEYS查询语句 pattern代表模板,有点像匹配表达式(不是正则),是redis的一种内置表达式,可以在里面使用通配符 底层存在一种模糊查询机制,效率并不高。当redis的数据量达到一定规模时(数百万上千万甚至更多),使用这种模糊查询机制会…...

Qt的window注册表读写以及删除

Qt的window注册表读写以及删除 1. 使用 QSettings&#xff08;Qt推荐方式&#xff09;基本操作关键点限制 2. 调用Windows原生API示例&#xff1a;创建/读取键值常用API注意事项 3. 高级场景(1) 递归删除键(2) 注册表权限修改 4. 安全性建议总结其他QT文章推荐 在Qt中操作Windo…...