JVM 基础、GC 算法与 JProfiler 监控工具详解

目录

1、引言

1.1 JVM内存与本地内存

1.2 JVM与JDK的关系

2、JVM基础

2.1 JVM(Java Virtual Machine)

2.2 Java与JVM的关系

2.3 JVM的内存结构

2.3.1 堆内存

2.3.2 栈内存

2.3.3 方法区

2.3.4 本地方法栈

2.3.5 程序计数器(PC寄存器)

2.4 JVM的位置

2.5 JVM的体系结构

2.6 JVM调优

3、类加载器及双亲委派机制

3.1 类加载器的作用

3.2 常见的类加载器

3.3 双亲委派机制

3.4 沙箱安全机制

4、Native方法与JNI(Java本地接口)

4.1 Native关键字

4.2 JNI的作用

5、程序计数器(PC寄存器)

5.1 定义

5.2 作用

6、方法区

6.1 定义

6.2 特点

7、Java栈与堆内存

7.1 栈

7.1.1数据结构

7.1.2 线程独立

7.1.3 栈溢出

7.2 堆内存

7.2.1 堆的结构

7.2.2 垃圾回收

7.2.3 堆内存溢出(OOM)

7.2.4 堆内存的调优

7.2.5 内存分配策略

8、 默认垃圾回收算法

8.1 分代垃圾回收

8.2 垃圾回收器的选择

8.3 总结

9、使用JProfiler工具分析OOM原因

9.1 OOM(OutOfMemoryError)分析

9.2 工具介绍

9.3 在IDEA中使用JProfiler

10、GC常见的算法

10.1 标记整理(标记压缩)

10.2 标记清除法

10.3 复制算法

10.4 引用计数器

10.5 GC算法总结

10.6 GC算法与分代收集

11、Java内存模型(JMM)


1、引言

1.1 JVM内存与本地内存

  • JVM内存 vs. 本地内存:

    在JVM中操作时,主要是使用JVM虚拟机的内存,这包括了堆内存(Heap)、方法区(Method Area)、栈内存(Stack)、本地方法栈(Native Method Stack)等。JVM负责管理和分配这部分内存。

    • 堆内存:用于存储对象实例,这是JVM主要使用的内存区域。
    • 栈内存:用于存储每个线程的局部变量、方法调用链等。
    • 方法区:用于存储类信息、常量、静态变量等。
    • 本地方法栈:用于调用本地(native)方法时使用的内存。

    JVM操作的这些内存都在其管理之下,虽然它运行在操作系统的本地环境中,但开发者一般不直接与操作系统的内存打交道。JVM虚拟内存是在操作系统的本地内存之上管理的。简单来说,JVM虚拟机的内存是操作系统为它分配的内存的一部分,它在此基础上进一步划分和管理。

1.2 JVM与JDK的关系

  • JVM和JDK的关系:

    当下载并安装JDK(Java Development Kit)时,JVM(Java Virtual Machine)就会自动包含在内。JVM是JDK中的一个核心组件,它负责执行Java字节码。JDK不仅包含JVM,还包括编译器(javac)、标准类库等开发工具。所以只要你安装了JDK,JVM就已经包含在你的环境中了,不需要单独下载。

2、JVM基础

2.1 JVM(Java Virtual Machine)

JVM是Java虚拟机,是运行Java程序的基础环境。它负责加载、执行Java字节码,并提供内存管理、垃圾回收等功能。Java的跨平台性正是由于JVM的存在,因为Java程序在不同操作系统上的JVM上运行,从而实现了“写一次,处处运行”的特性。

2.2 Java与JVM的关系

  • Java编译过程:Java源代码首先会通过编译器(如javac)编译成字节码(.class文件)。这个字节码并不直接运行在物理机器上,而是由JVM来解释和执行。
  • JVM的作用:JVM是Java程序运行时的核心,它接收和解释Java字节码,并将其转换为操作系统可执行的机器指令。通过JVM,Java程序可以跨平台运行,即同一份Java代码可以在不同操作系统上运行。

2.3 JVM的内存结构

官方JVM体系结构图

简易结构图

JVM内存结构分为多个区域,每个区域负责管理不同类型的数据和任务:

  • JVM垃圾介绍:
    • 堆内存中的垃圾:堆中存储所有对象实例,由于Java的自动内存管理机制,垃圾回收器(GC)会负责回收不再使用的对象,这些未使用的对象即为“垃圾”。
    • 方法区中的垃圾:虽然方法区存储类信息和常量,但在某些情况下,未被使用的类或静态数据也会被回收,因此方法区本质上也可能产生垃圾。
    • 栈内存中的数据:Java栈、本地方法栈和程序计数器中存储的是临时数据,比如局部变量、方法调用信息等。由于这些区域的生命周期与方法的执行周期相关,方法执行完毕后栈帧会自动释放,因此不会有垃圾存在。
2.3.1 堆内存
  • 堆(Heap):用于存储所有Java对象及数组。堆是垃圾回收器(GC)的主要工作区域,因为在这个区域中会产生垃圾对象。
2.3.2 栈内存
  • Java栈(Java Stack):存储局部变量、方法调用栈帧等。每个线程都有自己独立的Java栈,栈中不会存在垃圾对象,因为栈帧随方法执行结束自动释放。
2.3.3 方法区
  • 方法区(Method Area):存储已加载的类信息、常量、静态变量、即将编译的代码等。方法区本质上是堆内存的一部分,但用于特定用途。
2.3.4 本地方法栈
  • 本地方法栈(Native Method Stack):专门用于调用本地方法(使用非Java语言编写的方法,如C或C++),类似于Java栈。
2.3.5 程序计数器(PC寄存器)
  • 程序计数器(PC寄存器):存储当前线程执行的字节码的地址(程序指令),用于跟踪线程的执行进度。

2.4 JVM的位置

JVM运行在操作系统之上,充当了Java程序和底层操作系统之间的中间层。JVM实际上是一个软件,其主要实现通常是使用C语言编写的,部分实现还可能使用其他低级语言(如汇编)来优化性能。JVM负责屏蔽不同操作系统的细节,使Java程序能够在多种平台上运行。

2.5 JVM的体系结构

JVM的体系结构包括多个组成部分,主要分为以下几个模块:

  • 类加载器系统(Class Loader Subsystem):负责加载.class文件,验证、准备、解析和初始化类。
  • 运行时数据区(Runtime Data Area):包括堆、栈、方法区等,用于管理程序执行时的各种数据。
  • 执行引擎(Execution Engine):负责解释执行字节码或将字节码编译为本地机器码。
  • 本地方法接口(Native Interface):用于调用非Java编写的本地方法。
  • 垃圾回收系统(Garbage Collection System):自动管理堆中的对象回收。

2.6 JVM调优

JVM的性能优化通常主要针对堆和方法区进行。因为这两个区域负责管理Java对象、类信息和静态数据,并且会产生垃圾。通过调整堆的大小、垃圾回收策略、类加载和卸载等,可以提高应用的性能和内存使用效率。

  • JVM调优的几个常见方面:
    • 堆大小设置:通过-Xms-Xmx参数设置堆的初始大小和最大大小。
    • 垃圾回收器选择:不同的GC算法适合不同的场景,如G1适用于大内存应用,CMS适用于低延迟应用。
    • 方法区调优:通过调整方法区的大小和类卸载策略,防止内存溢出或类加载过多导致的性能问题。

3、类加载器及双亲委派机制

  • 类加载器及双亲委派机制:确保类加载的安全性和有效性,通过双亲委派避免核心类被恶意替换。

3.1 类加载器的作用

类加载器(ClassLoader)负责将.class文件加载到JVM中并转化为内存中的Class对象。具体来说,当你创建一个对象(如new Student())时,类加载器会加载该类的字节码文件,而引用对象存放在栈中,实际的对象数据存储在堆内存中。

3.2 常见的类加载器

JVM中存在多种类加载器,它们按层次结构组织,负责加载不同范围的类:

  1. 虚拟机自带的加载器:由JVM内部实现,用于加载JDK核心类。
  2. 启动类加载器(Bootstrap ClassLoader):又称为根类加载器,负责加载JVM核心库,通常是$JAVA_HOME/lib中的类,如rt.jar
  3. 扩展类加载器(Extension ClassLoader):用于加载扩展库,通常是$JAVA_HOME/lib/ext目录下的类。
  4. 应用程序类加载器(Application ClassLoader):负责加载用户类路径中的类,通常加载classpath中的类,是默认的类加载器。

3.3 双亲委派机制

双亲委派机制是一种类加载器的工作方式,用来避免类重复加载并保证Java核心类的安全性。

双亲委派机制的执行过程如下:

  1. 类加载请求:当某个类加载器接收到一个类的加载请求时,它不会立即尝试加载,而是将请求委派给它的父类加载器去处理。
  2. 逐级向上委派:每个类加载器都会将请求向上委托给父类加载器,直到最顶层的启动类加载器(Bootstrap ClassLoader)。
  3. 启动类加载器检查:启动类加载器检查是否能够加载该类,如果能,则加载并返回;否则将请求传递给子类加载器。
  4. 子类加载器处理:如果启动类加载器无法加载,才由子类加载器尝试加载。

注意:双亲委派机制的一个常见问题是如果我们定义了一个与JDK核心类(如java.lang.String)同名的类,它将永远不会被加载。因为启动类加载器会优先加载java.lang.String类,导致我们的自定义类无法加载,进而报错,如找不到main方法。

通过obj.getClass().getClassLoader()方法可以获取对象的类加载器,利用反射可以深入了解类加载器的工作机制。

3.4 沙箱安全机制

沙箱机制是一种保护机制,限制程序运行时的系统资源访问,防止恶意代码执行或访问敏感资源。类加载器在沙箱机制中扮演了重要角色,特别是采用了双亲委派机制,防止用户定义的恶意类替代核心类。

沙箱安全机制的组成:

  • 字节码校验器:确保字节码的正确性和安全性。
  • 类加载器:采用双亲委派机制防止类加载冲突。
  • 存取控制器:控制程序对文件、网络等系统资源的访问。
  • 安全管理器:提供更细粒度的安全策略控制。
  • 安全软件包:实现Java平台的安全功能,如加密、认证等。

4、Native方法与JNI(Java本地接口)

  • Native方法与JNI:允许Java调用底层代码,通过JNI扩展Java的使用范围。

4.1 Native关键字

native关键字用于声明本地方法,即用非Java语言(如C/C++)实现的方法。这些方法是因为Java无法直接实现某些底层操作,必须调用操作系统或底层库来完成。native方法调用时,会进入本地方法栈,并通过JNI(Java Native Interface,Java本地接口)与底层代码交互。

4.2 JNI的作用

JNI是Java与其他语言(如C/C++)进行交互的桥梁,主要作用是扩展Java的能力,让Java可以调用非Java的底层代码,尤其是在需要高性能或者与系统底层紧密相关的场景下(如硬件交互、系统调用等)。

5、程序计数器(PC寄存器)

  • PC寄存器:用于线程的字节码指令跟踪,是实现多线程的关键。

5.1 定义

程序计数器(Program Counter Register)是一个非常小的内存区域,每个线程都有一个独立的PC寄存器。它用来存储当前线程正在执行的字节码指令地址,指向下一条即将执行的指令。由于Java是多线程的,PC寄存器是线程私有的。

5.2 作用

程序计数器用于跟踪线程的执行进度,线程切换时通过它恢复到正确的执行位置,因此它是实现Java多线程的关键组件之一。

6、方法区

  • 方法区:用于存储类信息、静态变量、常量等,是JVM内存结构的重要组成部分。

6.1 定义

方法区(Method Area)是JVM内存的一个逻辑区域,它由所有线程共享,主要用于存储:

  • 已加载的类信息(类名、方法、字段等)
  • 运行时常量池(存储编译器生成的常量)
  • 静态变量
  • 类的字节码和方法(包括构造方法、接口定义等)

6.2 特点

  • 共享区域:方法区是线程共享的内存空间,不像栈和PC寄存器那样是线程私有的。
  • 存储内容:主要存储类的元数据、静态变量、常量池等,而对象实例是存储在堆中的。
  • 垃圾回收:尽管方法区存储静态信息,但在某些情况下(如类卸载)也会触发垃圾回收。

7、Java栈与堆内存

7.1 栈

7.1.1数据结构
  • 数据结构:栈是一种后进先出(LIFO,Last In First Out)的数据结构,只有栈顶的元素可以被访问和修改。
7.1.2 线程独立
  • 线程独立:每个线程都有自己的栈,栈的生命周期与线程相同。
  • 栈内存内容:
    • 八大基本数据类型(如intchar等)
    • 对象引用:指向堆中实际对象的引用
    • 方法调用:每当一个方法被调用时,相关信息(如局部变量、参数等)会存放在栈中。
7.1.3 栈溢出
  • 栈溢出

    栈溢出(Stack Overflow)通常发生在递归调用中,如果方法循环调用而没有终止条件,最终会耗尽栈空间,导致溢出错误。

7.2 堆内存

  • 堆内存

    • 单一堆:一个JVM实例只有一个堆内存,所有线程共享这个堆。
    • 堆内存的调节:可以通过JVM参数进行配置,通常会调整堆的初始大小和最大大小。
  • JVM实现

    三种常见的JVM实现:

    1. Sun公司的HotSpot
    2. BEA的JRockit
    3. IBM的J9 VM

    注意:从JDK 1.8开始,永久代(PermGen)被移除,改为使用元空间(Metaspace)来存储类的元数据。

7.2.1 堆的结构
  • 堆的结构

    堆内存通常被细分为几个区域:

    1. 新生区(Eden Space):
      • 对象在此区域被创建(使用new关键字)。
      • 如果新生区满了,会触发轻量级垃圾回收(轻GC)。
    2. 幸存者区(Survivor Space,分为S0和S1):
      • 新生区经过一次GC后存活的对象会被转移到这里。经过几次GC后仍然存活的对象可能被转移到老年代。
    3. 老年区(Old Generation):
      • 存放长时间存活的对象,通常是经历过多次GC的对象。
    4. 元空间(Metaspace):
      • 存放类的元数据,从JDK 1.8开始取代永久代。元空间使用本地内存,物理上不存在限制。
7.2.2 垃圾回收
  • 垃圾回收
    • 轻量级垃圾回收(轻GC):主要针对新生区的对象。
    • 重量级垃圾回收(重GC):通常针对老年区的对象,处理复杂和耗时。
7.2.3 堆内存溢出(OOM)
  • 堆内存溢出(OOM)
    • 当堆内存不足以满足对象创建需求时,会抛出OutOfMemoryError(OOM)。

    • 常见原因包括创建过多的对象,尤其是字符串等长生命周期的对象。

    • 图:

  • 字符串处理
    • 在Java中,字符串的长度是动态的,但受限于可用内存。大量字符串或过长字符串会导致堆内存溢出。
7.2.4 堆内存的调优
  • 堆内存的调优
    • 新生区调优:设置合适的大小以优化轻GC的频率和效率。
    • 老年区调优:通过调整老年区大小来减少重GC的次数
7.2.5 内存分配策略
  • JVM默认情况下分配的总内存通常是计算机内存的1/4,而初始化内存是1/64。可以通过命令行参数调整这些值。
  • 默认分配值(idea代码)
        public static void main(String[] args) {long max = Runtime.getRuntime().maxMemory();long total = Runtime.getRuntime().totalMemory();System.out.println("max" + max + "字节\t" + (max / (double) 1024 / 1024) + "MB");System.out.println("total" + total + "字节\t" + (total / (double) 1024 / 1024) + "MB");}
  • IDEA中进行JVM调参
  • 参数调优:JVM调优就是在这边地方调优。(调优区别:原本241MB内存大小,调成了981MB)
  • 参考:原始参数,下图是调优后的参数。(避免堆内存OOM错误)

    调优参数: -Xms1024m -Xmx1024m -XX:+PrintGCDetails

  • 控制台中:新生区(伊甸园)、老年区、元空间        
  • 总结
    • 栈用于存储方法调用和局部变量,每个线程都有独立的栈。
    • 堆用于存储对象,所有线程共享一个堆,内存分为新生区、幸存者区、老年区和元空间。
    • 垃圾回收的策略影响对象的生存周期与内存使用效率。
    • 堆内存的调优对于大型应用性能至关重要,合理配置内存可以有效防止OOM错误。

在 Java 中,垃圾回收器(GC,Garbage Collector)主要负责自动管理内存的分配和释放。Java 虚拟机(JVM)中的垃圾回收机制是基于 分代回收 理念的,这种机制认为对象的生命周期是不一样的,因此可以根据对象存活的时间长短采用不同的回收策略。

8、 默认垃圾回收算法

Java 的垃圾回收器默认使用 HotSpot VM,它采用的垃圾回收算法是 分代垃圾回收算法(Generational Garbage Collection),结合了多种不同的垃圾回收算法,具体包括:

  • 新生代回收算法:复制算法(Copying Algorithm)
  • 老年代回收算法:标记-清除算法(Mark-Sweep Algorithm)和 标记-整理算法(Mark-Compact Algorithm)

8.1 分代垃圾回收

  • 新生代:大多数新创建的对象会被分配在新生代。新生代中的对象大部分都是“朝生夕死”的,因此新生代的垃圾回收主要使用 复制算法,将存活对象从一个区域复制到另一个区域,非存活对象则直接被清理。

    • Eden 区:新对象首先分配在 Eden 区。
    • Survivor 区:对象在 Eden 区中经过一次垃圾回收后,如果没有被清理,会被移动到 Survivor 区。

    算法: 新生代中主要使用 复制算法(Copying Algorithm),它将存活的对象复制到另一个区域,而非存活的对象则会被回收。这种方法回收速度很快,因为它不需要遍历所有对象,只需处理存活的对象。

  • 老年代:新生代中经过多次垃圾回收后仍然存活的对象会被晋升到老年代。老年代中的对象通常存活时间较长,因此回收频率较低。

    算法:

    • 标记-清除算法(Mark-Sweep Algorithm):先标记出所有存活的对象,然后清理掉未标记的对象。缺点是容易产生内存碎片。
    • 标记-整理算法(Mark-Compact Algorithm):在标记完存活对象后,不仅清理掉未存活的对象,还会将存活对象整理到一起,避免内存碎片问题。

8.2 垃圾回收器的选择

虽然 Java 默认使用的是分代回收机制,但具体使用的垃圾回收器可以根据 JVM 的配置不同而变化,以下是常见的几种垃圾回收器:

  • Serial GC:一个简单的单线程垃圾回收器,适合单核 CPU 和小型应用。
  • Parallel GC:多线程垃圾回收器,适合多核 CPU 和注重吞吐量的应用。
  • G1 GC:一种面向服务端应用的垃圾回收器,旨在减少 GC 造成的停顿时间,替代了老年代的 CMS(Concurrent Mark-Sweep)回收器。
  • ZGC 和 Shenandoah GC:专注于极低停顿时间的垃圾回收器,适用于超低延迟应用。

8.3 总结

Java 默认采用的是基于 分代垃圾回收算法 的策略,其中新生代主要使用 复制算法,而老年代结合 标记-清除 和 标记-整理 算法。这种分代回收机制优化了内存管理,使得不同生命周期的对象能被高效回收。

9、使用JProfiler工具分析OOM原因

9.1 OOM(OutOfMemoryError)分析

  • OOM(OutOfMemoryError)分析
    • 内存快照分析:使用内存快照工具(如JProfiler、MAT)可以方便地查看在OOM发生时的内存状态,定位具体出错的代码行。
    • 代码行定位:通过内存快照分析,可以快速找到导致内存泄漏或堆溢出的代码位置,避免逐行调试的麻烦。

9.2 工具介绍

  • 工具介绍
    • MAT(Memory Analyzer Tool):用于分析Java堆转储文件,帮助定位内存泄漏、获取堆中对象的数据、找到占用内存大的对象等。
    • JProfiler:强大的性能分析工具,能够监控应用的内存使用情况,生成内存快照并分析内存泄漏。(实时监控)

9.3 在IDEA中使用JProfiler

  1. 插件安装:在IDEA中安装JProfiler插件,可以集成性能分析和监控功能。
  2. JProfiler官网上下载
    • 官网:ej-technologies - JProfiler
  3. 编写OOM异常代码
    • 在IDEA中编写可能导致OOM的代码,利用JProfiler监控具体行数:
      public class OOMExample {public static void main(String[] args) {List<String> list = new ArrayList<>();while (true) {list.add("This is a very long string that will keep consuming memory...");}}
      }
  4. 调参
    1. -Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError

    • -Xms:设置JVM的初始内存分配大小,建议设置为总内存的1/64(例如:-Xms512m)。

    • -Xmx:设置JVM的最大内存分配大小,建议设置为总内存的1/4(例如:-Xmx2048m)。

    • -XX:+PrintGCDetails:打印垃圾回收的详细信息,帮助分析内存使用情况和垃圾回收的效果。

  5. 监控软件使用
    • 配置
      • -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\Sachsen\Desktop\testKZ -Xms512m -Xmx512m 
    • 代码
          public static void main(String[] args) {String str = "zhangSan";while (true) {str += str + new Random().nextInt(1888888888) + new Random().nextInt(999999999);}}
    • java.lang.OutOfMemoryError 
    • 配置的文件目录下生成快照
    • 查看当前对象集
    • 查看栈溢出的对象(第一种方式)Current Object Set对象集传递引用查看
    • 查看栈溢出的对象(第二种方式)Current Object Set对象集图像结构查看
    • 查看栈溢出的对象(查看的第三种方式)Thread Dump线程转储查看 
      • 线程转储记录了快照时的所有线程,可以查看线程运行状态(运行、等待、阻塞等)和线程调用栈(展现线程执行的方法调用路径)。运行出现错误的线程会用一个特殊的图标标记。

  • 总结
    • 使用JProfiler和MAT等工具可以快速定位和分析OOM的原因,减少线下调试的时间。
    • 合理配置JVM内存参数有助于防止内存溢出。
    • 对于GC的了解能够帮助优化应用的内存使用和性能。

10、GC常见的算法

10.1 标记整理(标记压缩)

  • 概念:首先标记活着的对象,然后将它们整理到内存的一端,释放出连续的空闲空间。
  • 优点:减少了内存碎片,使内存使用更高效。
  • 缺点:需要额外的时间来移动对象。

10.2 标记清除法

  • 概念:标记所有活着的对象,然后直接清除未标记的对象。
  • 优点:实现简单,不需要额外空间。
  • 缺点:存在内存碎片,可能导致内存浪费。

10.3 复制算法

  • 概念:将存活的对象从Eden区复制到两个幸存者区中的一个(To区),当进行垃圾回收时,清空Eden区。
  • 工作过程:
    1. Eden区:每次GC时,将Eden区的存活对象复制到幸存者区的To区。
    2. 养老区:对象经历一定次数的GC(默认15次)后,若仍存活,则被转移到老年区。
  • 优点:内存利用率高,适合存活时间较短的对象。
  • 缺点:Eden和幸存者区可能会产生空闲区域,浪费内存。

10.4 引用计数器

  • 概念:为每个对象维护一个计数器,记录引用该对象的数量。当计数器为0时,自动回收对象。
  • 优点:简单易实现。
  • 缺点:无法处理循环引用,效率低,不推荐使用。

10.5 GC算法总结

内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)

内存整齐度:复制算法=标记压缩算法>标记清除算法

内存利用率:标记压缩算法=标记清除算法>复制算法

10.6 GC算法与分代收集

  • GC算法:通过不同的策略管理内存,优化性能与资源利用。
  • GC算法也称为分代收集算法,因为它利用了对象生命周期的特性,将对象分为新生代(Eden和幸存者区)和老年区。

11、Java内存模型(JMM)

  • JMM:确保多线程编程中内存访问的一致性和安全性。
  • 定义:Java内存模型规定了Java程序中线程如何访问共享内存,确保线程间的可见性与一致性。
  • 主要内容:
    • 主内存与工作内存:JMM将内存划分为主内存(共享内存)和工作内存(线程的私有内存)。
    • 内存屏障:确保特定的操作顺序和内存可见性。
    • 可见性:确保一个线程对共享变量的修改能被其他线程看到。
    • 原子性:保证对共享变量的操作是不可分割的。

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

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

相关文章

【MySQL 07】内置函数

目录 1.日期函数 日期函数使用场景&#xff1a; 2.字符串函数 字符串函数使用场景&#xff1a; 3.数学函数 4.控制流函数 1.日期函数 函数示例&#xff1a; 1.在日期的基础上加日期 在该日期下&#xff0c;加上10天。 2.在日期的基础上减去时间 在该日期下减去2天 3.计算两…

Android Context是什么?有很多的context他们之间有什么区别?什么时候该使用哪个?

目录 一、Context是什么&#xff1f; 在Android中&#xff0c;Context是一个抽象类 &#xff0c;它代表了应用程序的当前状态&#xff0c;包括资源和类加载器等&#xff0c;它提供了一个应用运行所需的信息&#xff0c;比如我们要获取资源 &#xff0c;那么需要她&#xff0c;…

雷池 WAF 如何配置才能正确获取到源 IP

经常有大哥反馈说雷池攻击日志里显示的 IP 有问题。 这里我来讲一下为什么一些情况下雷池显示的攻击 IP 会有问题。 问题说明 默认情况下&#xff0c;雷池会通过 HTTP 连接的 Socket 套接字读取客户端 IP。在雷池作为最外层网管设备的时候这没有问题&#xff0c;雷池获取到的…

【寻找one piece的算法之路】——双指针算法!他与她是否会相遇呢?

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;寻找one piece的刷题之路 什么是双指针算法 双指针算法是一种常用的编程技巧&#xff0c;尤其在处理数组和字符串问题时非常有效。这种方法的核心思想是使用两个指针来遍历数据结构&#xff0c;这两…

【HTML+CSS】仿电子美学打造响应式留言板

创建一个响应式的留言板 在这篇文章中&#xff0c;我们将学习如何创建一个简单而美观的留言板&#xff0c;它将包括基本的样式和动画效果&#xff0c;以及响应式设计&#xff0c;确保在不同设备上都能良好显示。 HTML 结构 首先&#xff0c;我们创建基本的HTML结构。留言板由…

Android SQLite的基本使用、生成Excel文件保存到本地

1. Android SQLite的基本使用 1.1. SQLiteOpenHelper Android 底层已经通过一个SQLiteOpenHelper的抽象类将数据库的创建&#xff0c;以及修改&#xff0c;更新等都放在了里面。 要使用它必须实现它的OnCreate(SQLiteDatabase db)&#xff0c;onUpgrade(SQLiteDatabase db, int…

YOLOv11改进 | 独家创新- 注意力篇 | YOLOv11结合全新多尺度线性注意力机制MLAttention(全网独家创新)

1. MLAttention介绍 (1). 多尺度卷积操作&#xff1a;MLAttention通过多尺度卷积操作来增强不同尺度的特征表达能力。采用了多种卷积核尺寸&#xff08;例如5x5、1x7、7x1、1x11、11x1、1x21、21x1&#xff09;的深度可分离卷积来捕捉不同感受野的特征。较小的卷积核擅长捕捉细…

TypeScript 算法手册【快速排序】

文章目录 1. 快速排序简介1.1 快速排序定义1.2 快速排序特点 2. 快速排序步骤过程拆解2.1 选择基准元素2.2 划分数组2.3 递归排序 3. 快速排序的优化3.1 三数取中法选择基准3.2 插入排序与快速排序结合案例代码和动态图 4. 快速排序的优点5. 快速排序的缺点总结 【 已更新完 Ty…

C语言基础(7)之操作符(1)(详细介绍)

目录 1. 各种操作符介绍 1.1 操作符汇总表 2. 移位操作符 2.1 移位操作符知识拓展 —— 原码、反码、补码 2.2 移位操作符讲解 2.2.1 右移操作符 ( >> ) 2.2.2 左移操作符 ( << ) 3. 位操作符 3.1 & (按位与) 3.2 | (按位或) 3.3 ^ (按位异或) 3.4…

排序算法之——归并排序,计数排序

文章目录 前言一、归并排序1. 归并排序的思想2. 归并排序时间复杂度及空间复杂度3. 归并排序代码实现1&#xff09;递归版本2&#xff09;非递归版本 二、计数排序1. 计数排序的思想2. 计数排序的时间复杂度及空间复杂度3. 计数排序代码实现 总结&#xff08;排序算法稳定性&am…

【JavaEE】——线程池大总结

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c; 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 引入&#xff1a;问题引入 一&#xff1a;解决方案 1&#xff1a;方案一——协程/纤程 &#xff08;1…

【完-网络安全】Windows注册表

文章目录 注册表启动项及常见作用五个根节点常见入侵方式 注册表 注册表在windows系统的配置和控制方面扮演了一个非常关键的角色&#xff0c;它既是系统全局设置的存储仓库&#xff0c;也是每个用户的设置信息的存储仓库。 启动项及常见作用 快捷键 WinR打开运行窗口&#x…

【C++】C++基础

目录 一. C关键字(C98) 二、C的第一个程序 三、命名空间 3.1.namespace的价值 3.2.namespace的定义 3.2.命名空间使用 总结&#xff1a;在项目当中第一、第二种方法搭配使用&#xff0c;第三种冲突风险非常大&#xff0c;仅适合练习使用。 四、C输入&输出 五、缺省…

调试分析:[跳数度量]更改为[距离度量]后的 routing_bellmanford 算法

回顾复习2023年8月的《★修改Exata6.2源码&#xff1a;〔修改Bellmanford最短路径路由的衡量标准从【路由跳数】改为【“路由器节点间的物理距离”】&#xff0c;并动画演示〕》&#xff0c;VS2015调试Exata&#xff0c;跟踪调试修改后的[ routing_bellmanford.cpp ]源码&#…

k8s架构,从clusterIP到光电半导体,再从clusterIP到企业管理

clusterIP作为k8s中的服务&#xff0c; 也是其他三个服务的基础 ~]$ kubectl create service clusterip externalname loadbalancer nodeport 客户端的流量到service service分发给pod&#xff0c;pod由控制器自动部署&#xff0c;自动维护 那么问题是service的可用…

计算机网络期末复习真题(附真题答案)

前言&#xff1a; 本文是笔者在大三学习计网时整理的笔记&#xff0c;哈理工的期末试题范围基本就在此范畴内&#xff0c;就算真题有所更改&#xff0c;也仅为很基础的更改数值&#xff0c;大多跑不出这些题&#xff0c;本文包含简答和计算等大题&#xff0c;简答的内容也可能…

【RADARSAT Constellation Mission(RCM)卫星星座简介】

RADARSAT Constellation Mission&#xff08;RCM&#xff09;卫星星座是加拿大太空局&#xff08;CSA&#xff09;的下一代C波段合成孔径雷达&#xff08;SAR&#xff09;卫星星座&#xff0c;以下是对其的详细介绍&#xff1a; 一、基本信息 发射时间&#xff1a;2019年6月…

基于微信小程序的四六级词汇+ssm(lw+演示+源码+运行)

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;四六级词汇小程序被用户普遍使用&#xff0c;为方便用户能…

容器适配器-stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack&#xff08;栈&#xff09; 4.queue&#xff08;队列&#xff09; 5.仿函数 6.priority_queue&#xff08;优先级队列&#xff09;&#xff08;堆…

微信小程序map组件自定义气泡真机不显示

最近遇到一个需求需要使用uniapp的map自定义气泡 &#xff0c;做完之后发现在模拟器上好好的&#xff0c;ios真机不显示&#xff0c;安卓页数时好时不好的 一番查询发现是小程序的老问题了&#xff0c;网上的方法都试了也没能解决 后来看到有人说用nvue可以正常显示&#xff0c…