java虚拟机内存管理

文章目录

    • 概要
    • 一、jdk7与jdk8内存结构的差异
    • 二、程序计数器
    • 三、虚拟机栈
      • 3.1 什么是虚拟机栈
      • 3.2 什么是栈帧
      • 3.3 栈帧的组成
    • 四、本地方法栈
    • 五、堆
      • 5.1 堆的特点
      • 5.2 堆的结构
      • 5.3 堆的参数配置
    • 六、方法区
      • 6.1 方法区结构
      • 6.2 运行时常量池
    • 七、元空间

概要

根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。

在这里插入图片描述
其中各个部分的概述如下:

名称特征作用配置参数异常
程序计数器线程私有,生命周期与线程相同字节码行号指示器
虚拟机栈线程私有,生命周期与线程相同,使用连续的内存空间存储信息如上图-XssStackOverflowError/
OutOfMemoryError
线程共享,生命周期与虚拟机相同,可以不使用连续的内存地址保存对象实例,所有对象实例(包括数组)都要在堆上分配-Xms -Xsx -XmnOutOfMemoryError
方法区线程共享,生命周期与虚拟机相同,
可以不使用连续的内存地址
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据-XX:PermSize:16M
-XX:MaxPermSize64M
-XX:MetaspaceSize=16M
-XX:MaxMetaspaceSize=64M
OutOfMemoryError
本地方法栈线程私有为虚拟机使用到的Native 方法服务StackOverflowError/
OutOfMemoryError

JVM分为五大模块: 类装载器子系统 、 运行时数据区 、 执行引擎 、 本地方法接口 和 垃圾收集模块 。

在这里插入图片描述

一、jdk7与jdk8内存结构的差异

Java7和Java8内存结构的不同主要体现在方法区的实现
方法区是java虚拟机规范中定义的一种概念上的区域,不同的厂商可以对虚拟机进行不同的实现。
我们通常使用的Java SE都是由Sun JDKOpenJDK所提供,这也是应用最广泛的版本。而该版本使用的VM就是HotSpot VM。通常情况下,我们所讲的java虚拟机指的就是HotSpot的版本。

JDK7的内存结构
在这里插入图片描述
永久代是 hotspot 在1.7及之前才有的设计,1.8+,以及其他虚拟机并不存。可以说,永久代是1.7的 hotspot 偷懒的结果,他在堆里划分了一块来实现方法区的功能,叫永久代
因为这样可以借助堆的垃圾回收来管理方法区的内存,而不用单独为方法区再去编写内存管理程序。
同时代的其他虚拟机,如 J9 , Jrockit 等,没有这个概念。后来 hotspot认识到,永久代来做这件事不是一个好主意。1.7已经从永久代拿走了一部分数据(静态变量和运行时常量池转移到了堆中),直到1.8+彻底去掉了永久代,方法区大部分迁移到了 metaspace (注意不是全部,不是全部)

JDK8的内存结构
在这里插入图片描述
从jdk1.8开始已经将方法区中实现的永久代去掉了,并用元空间( class metadata space )代替了之前的永久代,元空间的存储位置是:本地内存/直接内存,并且将方法区大部分迁移到了元空间。

方法区Java8之后的变化小结:

  • 移除了永久代(PermGen),替换为元空间(Metaspace
  • 永久代中的class metadata(类元信息)转移到了native memory(本地内存,而不是虚拟机)
  • 永久代中的interned Strings(字符串常量池) 和 class static variables(类静态变量)转移到了Java heap
  • 永久代参数(PermSize MaxPermSize)-> 元空间参数(MetaspaceSize MaxMetaspaceSize

Java8 为什么使用元空间替代永久代,这样做有什么好处呢?

官方给出的解释是:

  1. 移除永久代是为了融合 HotSpot JVM 与 JRockit VM 而做出的努力,因为 JRockit 没有永久代,所以不需要配置永久代。
  2. 永久代内存经常不够用或发生内存溢出,抛出异常java.lang.OutOfMemoryError: PermGen 。这是因为在 JDK1.7 版本中,指定的 PermGen 区大小为8M,由于 PermGen 中类的元数据信息在每次 FullGC 的时候都可能被收集,但回收率都偏低,成绩很难令人满意;
  3. PermGen 分配多大的空间很难确定,PermSize 的大小依赖于很多因素,比如,JVM 加载的 class 总数、常量池的大小和方法的大小等,而jdk1.8以后的元空间大小就只受本机总内存的限制(如果不设置参数的话),因为它使用的是本地内存。

二、程序计数器

程序计数器(Program Counter Register):也叫PC寄存器,是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令、分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

PC寄存器的特点

(1)区别于计算机硬件的pc寄存器,两者不略有不同。计算机用pc寄存器来存放“伪指令”或地址,而相对于虚拟机,pc寄存器它表现为一块内存,虚拟机的pc寄存器的功能也是存放伪指令,更确切的说存放的是将要执行指令的地址。
(2)当虚拟机正在执行的方法是一个本地(native)方法的时候,jvm的pc寄存器存储的值是undefined
(3)程序计数器是线程私有的,它的生命周期与线程相同,每个线程都有一个。
(4)此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

在这里插入图片描述
Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处
理器只会执行一条线程中的指令。
因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数
器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

三、虚拟机栈

3.1 什么是虚拟机栈

Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,即生命周期和线程相同。Java虚拟机栈和线程同时创建,用于存储栈帧。每个方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

在这里插入图片描述

public class StackDemo {public static void main(String[] args) {StackDemo sd = new StackDemo();sd.A();}public void A() {int a = 10;System.out.println(" method A start");System.out.println(a);B();System.out.println("method A end");}public void B() {int b = 20;System.out.println(" method B start");C();System.out.println("method B end");}private void C() {int c = 30;System.out.println(" method C start");System.out.println("method C end");}
}

在这里插入图片描述

3.2 什么是栈帧

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。
在这里插入图片描述

3.3 栈帧的组成

栈帧大体都包含四个区域:局部变量表、操作数栈、动态连接、 返回地址

局部变量表
部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内定义的局部变量。
包括8种基本数据类型、对象引用(reference类型)和returnAddress类型(指向一条字节码指令的地址)。其中64位长度的longdouble类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。

操作数栈

操作数栈(Operand Stack)也称作操作栈,是一个后入先出栈(LIFO)。随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。

操作数栈作用小结:

  1. 主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间
  2. 操作数栈就是JVM执行引擎的一个工作区, Java虚拟机的解释执行引擎被称为"基于栈的执行引擎",其中所指的栈就是指-操作数栈
  3. 为了实现java的跨平台,选择了面向操作数栈的指令集架构而没有选择直接基于CPU寄存器的指令集架构(由执行引擎面向更底层),基于栈的指令集主要的优点就是可移植,寄存器由硬件直接提供,程序直接依赖这些硬件寄存器则不可避免地要受到硬件的约束,但是栈架构指令集的主要缺点是执行速度相对来说会稍慢一些,因为栈实现在内存之中,频繁的栈访问也就意味着频繁的内存访问,相对于CPU来说,内存始终是执行速度的瓶颈;

动态链接
Java虚拟机栈中,每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,持有这个引用的目的是为了支持方法调用过程中的动态链接(Dynamic Linking)。
动态链接的作用是将符号引用转换成直接引用

返回地址
方法返回地址存放调用该方法的PC寄存器的值。一个方法的结束,有两种方式:正常地执行完成,出现未处理的异常非正常的退出。无论通过哪种方式退出,在方法退出后都返回到该方法被调用的位置。方法正常退出时,调用者的PC计数器的值作为返回地址,即调用该方法的指令的下一条指令的地址。而通过异常退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息。
无论方法是否正常完成,都需要返回到方法被调用的位置,程序才能继续进行。

四、本地方法栈

本地方法栈(Native Method Stacks) 与虚拟机栈所发挥的作用是非常相似的, 其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码) 服务, 而本地方法栈则是为虚拟机使用到的本地(Native) 方法服务。
特点:

  1. 本地方法栈加载native方法
  2. 是线程私有,生命周期跟线程相同,每个线程都有一个
  3. 跟java虚拟虚拟机栈一样,规定了两种类型异常:
    a) StackOverFlowError :线程请求的栈深度大于所允许的深度。
    b) OutOfMemoryError:本地方法栈扩展时无法申请到足够的内存

五、堆

对于Java应用程序来说, Java堆(Java Heap) 是虚拟机所管理的内存中最大的一块。 Java堆是被所 有线程共享的一块内存区域, 在虚拟机启动时创建。 此内存区域的唯一目的就是存放对象实例, Java 世界里“几乎”所有的对象实例都在这里分配内存。

5.1 堆的特点

  1. Java虚拟机所管理的内存中最大的一块
  2. jvm所有线程共享(堆中也包含私有的线程缓冲区 Thread Local Allocation Buffer (TLAB)
  3. 在虚拟机启动时创建
  4. 几乎所有的对象实例以及数组都在这里分配内存
  5. java堆时垃圾收集器管理的主要区域
  6. 从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆还可以细分为:新生代和老年代;新生代又可以分为:Eden 空间、From Survivor空间、To Survivor空间。
  7. 堆是计算机物理存储上不连续的、逻辑上是连续的,也是大小可调节的(通过-Xms-Xmx控制)。
  8. 方法结束后,堆中对象不会马上移出仅仅在垃圾回收的时候时候才移除
  9. 如果在堆中没有内存完成实例的分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常

5.2 堆的结构

现在垃圾回收器都使用分代理论,堆空间也分类如下:
在Java7 Hotspot虚拟机中将Java堆内存分为3个部分:

  • 青年代Young Generation
  • 老年代Old Generation
  • 永久代Permanent Generation

在这里插入图片描述
在Java8以后,由于方法区的内存不在分配在Java堆上,而是存储于本地内存元空间Metaspace中,所以永久代就不存在了

在这里插入图片描述

5.3 堆的参数配置

参考:参数配置

JVM中存储java对象可以被分为两类:

  1. 年轻代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。年轻代分成1个Eden Space和2个Suvivor Spacefromto)。
  2. 年老代(Tenured Gen):年老代主要存放JVM认为生命周期比较长的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁.

-XX:NewRatio=ratio
Sets the ratio between young and old generation sizes. By default, this option is set to 2. The following example shows how to set the young/old ratio to 1:
-XX:NewRatio=1

-XX:NewRatio=2:默认值,标识新生代占1,老年代占2,新生代占整个堆的1/3;
修改占比 -XX:NewPatio=4 , 标识新生代占1 , 老年代占4 , 新生代占整个堆的1/5

XX:SurvivorRatio=ratio
Sets the ratio between eden space size and survivor space size. By default, this option is set to 8. The following example shows how to set the eden/survivor space ratio to 4:
-XX:SurvivorRatio=4

Eden空间和另外两个Survivor空间占比分别为8:1:1
可以通过操作选项 -XX:SurvivorRatio 调整这个空间比例。 比如 -XX:SurvivorRatio=8

在这里插入图片描述
堆的总大小可由-Xms -Xmx来配置

JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着的。因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

六、方法区

方法区(Method Area) 与Java堆一样, 是各个线程共享的内存区域, 它用于存储已被虚拟机加载的类型信息、常量、 静态变量、 即时编译器编译后的代码缓存等数据。
官方文档:方法区

方法区中存储的信息大致可分以下两类:

  1. 类信息:主要指类相关的版本、字段、方法、接口描述、引用等
  2. 运行时常量池:编译阶段生成的常量与符号引用、运行时加入的动态变量

方法区在虚拟机规范里这是一个逻辑概念,元空间、永久代是方法区具体的落地实现。

在这里插入图片描述
在jdk1.6里,用永久代来实现方法区,物理空间上用的时堆的内存(目的是利用堆的垃圾回收来管理方
法区的内存)。字符串常量是运行时常量池的一部分,也就是归属于方法区,放在了永久代里。这个时候经常会出现的一个错误就是:java.lang.OutOfMemoryError: PermGen space
jdk1.7已经从永久代拿了一部分数据(静态变量和运行时常量池)转移到了堆中

6.1 方法区结构

在这里插入图片描述
类加载器将Class文件加载到内存之后,将类的信息存储到方法区中

方法区中存储的内容:

  • 类型信息(域信息、方法信息)
  • 运行时常量池

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

  • 这个类型的完整有效名称(全名 = 包名.类名)
  • 这个类型直接父类的完整有效名(对于 interface或是java.lang.Object,都没有父类)
  • 这个类型的修饰符( public,abstract,final的某个子集)
  • 这个类型直接接口的一个有序列表

域信息
域信息,即为类的属性,成员变量
JVM必须在方法区中保存类所有的成员变量相关信息及声明顺序。
域的相关信息包括:域名称、域类型、域修饰符(pυblicprivateprotectedstaticfinalvolatiletransient的某个子集)

方法信息
JVM必须保存所有方法的以下信息,同域信息一样包括声明顺序:

  1. 方法名称方法的返回类型(或void
  2. 方法参数的数量和类型(按顺序)
  3. 方法的修饰符publicprivateprotectedstaticfinalsynchronizednativeabstract的一个子集
  4. 方法的字节码bytecodes、操作数栈、局部变量表及大小( abstractnative方法除外)
  5. 异常表( abstractnative方法除外)。每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏
    移地址、被捕获的异常类的常量池索引

6.2 运行时常量池

在jvm规范中,方法区除了存储类信息之外,还包含了运行时常量池。这里
首先要来讲一下常量池的分类:

  • Class常量池(静态常量池)
  • 运行时常量池
  • 字符串常量池(没有明确的官方定义,其目的是为了更好地使用String

常量池经常会被搞混,要准确地理解,首先来看基本定义

静态常量池:存放编译期间生成的各种字面量与符号引用
运行时常量池:常量池表在运行时的表现形式

编译后的字节码文件中包含了类型信息、域信息、方法信息等。通过ClassLoader将字节码文件的常量池(静态常量池)中的信息加载到内存中,存储在了方法区的运行时常量池中。

什么叫字面量与符号引用呢?

静态常量池

.class 文件中除了有类的版本、字段、方法和接口等描述信息外,还有一项信息是常量池 ( Constant Pool Table ),用于存放编译期间生成的各种字面量和符号引用,之所以说它是静态的常量池是因为这些都只是躺在 .class 文件中的静态数据,此时还没被加载到内存.

/*** 1. 使用jdk1.8编译* 2. 使用 javap -v ClassConstantPool.class*/
public class ClassConstantPool {private static String a = "abc";private String f = "def";private static int b = 123;private final int c = 456;private int d = 789;private float e;Gucci gucci = new Gucci();class Gucci {}
}

反编译后,截取部分信息如下:
在这里插入图片描述

字面量:给基本类型变量的赋值就叫做字面量或字面值,字面量是编译后生成的产物。
比如:String a = "b",这里的“b”就是字符串字面量,同样类推还有整数字面量,浮点类型字面量,字符字面量
符号引用:符号引用以一组符号来描述所引用的目标。符号引用可以是任何形式的字面量,JAVA 在编译的时候一个每个 java 类都会被编译成一个 class 文件,但在编译的时候虚拟机并不知道所引用类的地址(实际地址),就用符号引用来代替,而在类的解析阶段(类加载的一个过程)就是为了把这个符号引用转化成为真正的地址。
比如: ClassConstantPool 类被编译成一个 class 文件时,发现引用了 Gucci 类,,但是在编译时并不知道 Gucci 类的实际内存地址,因此只能使用符号引用( com/ocean/constance/ClassConstantPool$Gucci )来代替。而在类装载器装
Guuci 类时,此时可以通过虚拟机获取 Guuci类 的实际内存地址,因此便可以将符号 com/ocean/constance/ClassConstantPool$Gucci 替换为 Guuci 类的实际内存地址。

运行时常量池

运行时常量池( Runtime Constant Pool )是每一个类或接口的常量池( Constant_Pool )的运行时表示形式,它包括了若干种不同的常量:从编译期可知的数值字面量到必须运行期解析后才能获得的方法或字段引用。

运行时常量池是在类加载完成之后,将 静态常量池中的符号引用值转存到运行时常量池中,类在解析之后,将符号引用替换成直接引用。 另外运行时常量池的物理存储位置要注意两点:

  1. 运行时常量池在 JDK1.7 版本之后,就移到堆内存中了,这里指的是物理空间,而逻辑上还是属于方法区(方法区是逻辑分区)。
  2. 在 JDK1.8 中,使用元空间代替永久代来实现方法区,但是方法区从定义上并没有改变,所谓 “Your father will always be your father” 。变动的只是方法区中内容的物理存放位置,运行时常量池和字符串常量池被移动到了堆中而并没有在元空间。但是不论它们物理上如何存放,逻辑上还是属于方法区的。

字符串常量池

字符串常量池这个概念是有争议的,很多正式的虚拟机规范文档,都没有对这个概念作一个明确的官方定义。

以 JDK1.8 为例,字符串常量池是存放在堆中,并且与 java.lang.String类有很大关系。设计这块内存区域的原因在于: String 对象作为 Java 语言中重要的数据类型,是内存中占据空间最大的一个对象。高效地使用字符串,可以提升系统的整体性能。

七、元空间

在JDK1.7之前,HotSpot 虚拟机用永久代来实现方法区。而从 JDK 1.8 开始,移除永久代,用元空间来实现方法区,它位于本地内存中,而不是虚拟机内存中。

永久代跟元空间对比如下:

  • 存储位置不同:永久代在物理上是堆的一部分,和新生代、老年代的地址是连续的,而元空间属于本地内存。
  • 存储内容不同:在原来的永久代划分中,永久代用来存放类的元数据信息、静态变量以及常量池等。现在类的元信
    息存储在元空间中,静态变量和常量池等并入堆中,相当于原来的永久代中的数据,被元空间和堆内存给瓜分了。

Metaspace相关参数:

  • XX:MetaspaceSize·,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如
    果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
  • -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。如果没有使用该参数来设置类的元数据的大小,其最大可利用空间是整个系统内存的可用空间。JVM也可以增加本地内存空间来满足类元数据信息的存储。但是如果没有设置最大值,则可能存在bug导致Metaspace的空间在不停的扩展,会导致机器的内存不足;进而可能出现swap内存被耗尽;最终导致进程直接被系统直接kill掉。如果设置了该参数,当Metaspace剩余空间不足,会抛出:java.lang.OutOfMemoryError: Metaspace space
  • -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
    -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

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

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

相关文章

探索小红书笔记API:挖掘数据背后的故事

随着数字化时代的到来,数据已经成为企业和个人决策的重要依据。小红书作为一个流行的社交电商平台,积累了大量的用户数据和内容。通过探索小红书笔记API,我们可以深入挖掘这些数据背后的故事,从而更好地理解用户需求和市场趋势。 …

弱电工程计算机网络系统基础知识

我们周围无时无刻不存在一张网,如电话网、电报网、电视网、计算机网络等;即使我们身体内部也存在许许多多的网络系统,如神经系统、消化系统等。最为典型的代表即计算机网络,它是计算机技术与通信技术两个领域的结合。 计算机网络的…

《Spring Cloud学习笔记:微服务保护Sentinel + JMeter快速入门》

Review 解决了服务拆分之后的服务治理问题:Nacos解决了服务治理问题OpenFeign解决了服务之间的远程调用问题网关与前端进行交互,基于网关的过滤器解决了登录校验的问题 流量控制:避免因为突发流量而导致的服务宕机。 隔离和降级&#xff1a…

八股文打卡day12——计算机网络(12)

面试题:HTTPS的工作原理?HTTPS是怎么建立连接的? 我的回答: 1.客户端向服务器发起请求,请求建立连接。 2.服务器收到请求之后,向客户端发送其SSL证书,这个证书包含服务器的公钥和一些其他信息…

LVS那点事

LVS 原理 IPVS LVS 的 IP 负载均衡技术是通过 IPVS 模块来实现的,IPVS 是 LVS 集群系统的核心软件,它的主要作用是:安装在 Director Server 上,同时在 Director Server 上虚拟出一个 IP 地址,用户必须通过这个虚拟的…

k8s的二进制部署: 源码包部署-----node节点部署

服务器IP软件包k8s--master0120.0.0.61kube-aplserver,kube-controer-manager,kube-scheduler,etcdk8s--master0220.0.0.62kube-controer-manager,kube-schedulernode节点0120.0.0.62kubelet,kube-proxy,et…

初识javaWeb

一、JavaWeb是什么? 1、概念 javaWeb指的是使用java语言进行互联网领域项目开发的技术栈——进行web项目开发所需的技术的集合。 -Web前端——在浏览器中用户可以看到的网页 -Web后端——为前端提供数据的程序 2、Web项目 java语言是可以进行多种类型的项目开发&a…

信号处理设计模式

问题 如何编写信号安全的应用程序? Linux 应用程序安全性讨论 场景一:不需要处理信号 应用程序实现单一功能,不需要关注信号 如:数据处理程序,文件加密程序,科学计算程序 场景二:需要处理信…

计算机毕业设计------ssm茶叶溯源系统

项目介绍 茶叶溯源系统,分为前台与后台。普通用户可在前台通过18位的编码查询茶叶的出售历史。 后台分为两种角色,管理员与经销商; 管理员主要功能包括: 主界面; 管理员管理:管理员列表、添加管理员&am…

SparkStreaming_window_sparksql_reids

1.5 window 滚动窗口滑动窗口 window操作就是窗口函数。Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作。每次掉落在窗口内的RDD的数据,会被聚合起来执行计算操作,然后生成的RDD,会…

设计模式——行为型模式

模板方法模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间…

PHP序列化总结3--反序列化的简单利用及案例分析

反序列化中生成对象里面的值,是由反序列化里面的值决定,与原类中预定义的值的值无关,穷反序列化的对象可以使用类中的变量和方法 案例分析 反序列化中的值可以覆盖原类中的值 我们创建一个对象,对象创建的时候触发了construct方…

基于QT开发的温室气体数据记录软件

1、概述 温室气体分析仪数据记录软件用于实现温室气体分析仪数据的获取与存储,阀箱数据的获取与存储、冷阱数据的获取与存储、采样单元数据的获取与存储、阀箱和采样单元的远程操作以及系统功能的管理。其主操作界面如下: 上述软件界面分为2各区域&…

【Linux】内核编译 镜像制作

文章目录 一、Ubuntu内核编译1.1 为什么自己编译内核1.2 Ubuntu 内核源码下载1.21 内核的作用1.22 Linux内核与ubuntu内核1.23 Ubuntu内核源码获取 1.3 在Windows系统下编译ubuntu内核1.4 在Linux系统下编译ubuntu内核 二、镜像制作 一、Ubuntu内核编译 1.1 为什么自己编译内核…

IIS服务器发布PHP网站

IIS服务器,相信开发者都不会陌生,它的英文全称是Internet Information Services,是由微软公司提供的基于运行Microsoft Windows的互联网基本服务,常用于Windows系统的Web项目部署,本篇以PHP项目为例,讲解如…

Qt 中使用 MySQL 数据库保姆级教程(上)

作者:billy 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 前言 在 Qt 中默认只搭载了 QSqlLite 数据库驱动,若要使用其他数据库需要自己下载数据库,并将数据库驱动加载到…

GitOps实践指南:GitOps能为我们带来什么?

Git,作为开发过程中的核心工具,提供了强大的版本控制功能。即便在写代码的时候稍微手抖一下,我们也能通过 Git 的差异对比(diff)轻松追踪到庞大工程中的问题,确保代码的准确与可靠。这种无与伦比的自省能力…

【小沐学Python】Python实现免费天气预报获取(OpenWeatherMap)

文章目录 1、简介1.1 工具简介1.2 费用1.3 注册1.4 申请key 2、接口说明2.1 One Call 3.02.2 Current Weather and Forecasts collection2.2.1 API 调用2.2.2 API 参数 2.3 Historical Weather collection2.4 Weather Maps collection2.5 Other weather APIs 3、接口测试3.1 例…

SpringBoot集成支付宝,看这一篇就够了。

前 言 在开始集成支付宝支付之前,我们需要准备一个支付宝商家账户,如果是个人开发者,可以通过注册公司或者让有公司资质的单位进行授权,后续在集成相关API的时候需要提供这些信息。 下面我以电脑网页端在线支付为例,介…

HTML教程(1)——概述和第一个网页

一、什么是HTML HTML 是用来描述网页的一种语言。 HTML 指的是超文本标记语言 (Hyper Text Markup Language)HTML 不是一种编程语言,而是一种标记语言 (markup language)标记语言是一套标记标签 (markup tag)HTML 使用标记标签来描述网页 二、什么是HTML 标签 H…