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

JVM内存结构笔记04-字符串常量池

文章目录

  • 定义
    • 字符串常量池的位置
    • JDK 1.7 为什么要将字符串常量池移动到堆中?
  • StringTable
    • 案例1
    • 案例2
    • 案例3
  • String.intern()
    • 案例4
    • 案例5
    • 案例6
    • 总结
  • StringTable 垃圾回收案例
    • 1.创建100个字符串(不会触发垃圾回收)
    • 2.创建10000个字符串(触发垃圾回收)
  • StringTable 性能调优
    • 1.调整StringTable哈希桶个数参数:调整 -XX:StringTableSize=桶个数
    • 2.考虑将字符串对象是否入池
  • 常量池和运行时常量池、字符串常量池三者之间的关系


在这里插入图片描述

定义

字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

// 在字符串常量池中创建字符串对象 ”ab“
// 将字符串对象 ”ab“ 的引用赋值给给 aa
String aa = "ab";
// 直接返回字符串常量池中字符串对象 ”ab“,赋值给引用 bb
String bb = "ab";
System.out.println(aa==bb); // true
  • HotSpot 虚拟机中字符串常量池的实现是 src/hotspot/share/classfile/stringTable.cpp
  • StringTable 可以简单理解为一个固定大小的HashTable ,容量为 StringTableSize(可以通过 -XX:StringTableSize 参数来设置)。
  • 保存的是字符串(key)和 字符串对象的引用(value)的映射关系,字符串对象的引用指向堆中的字符串对象。

字符串常量池的位置

JDK1.7 之前,方法区的具体实现是永久代(Permanent Generation),字符串常量池存放在方法区(永久代)。
在这里插入图片描述
JDK 7 开始,字符串常量池和静态变量从永久代中移动到了 Java 堆中,但方法区仍然由永久代实现。这一改变主要是为了避免永久代的内存溢出问题,因为永久代的空间相对较小,且难以进行调优,而堆的管理相对更加灵活。
在这里插入图片描述
JDK 8 及以后的版本中,永久代被元空间(Metaspace)所取代,但字符串常量池仍然在堆中。元空间使用的是本地内存,不再受 JVM 堆内存的限制。方法区由元空间实现,它主要存储类的元数据信息,而字符串常量池独立于元空间,在堆中进行管理。

JDK 1.7 为什么要将字符串常量池移动到堆中?

主要是因为永久代(方法区实现)的 GC 回收效率太低,只有在整堆收集 (Full GC)的时候才会被执行 GC。Java 程序中通常会有大量的被创建的字符串等待回收,将字符串常量池放到堆中,能够更高效及时地回收字符串内存。

注意:运行时常量池、方法区、字符串常量池这些都是不随虚拟机实现而改变的逻辑概念,是公共且抽象的,Metaspace、Heap 是与具体某种虚拟机实现相关的物理概念,是私有且具体的。

StringTable

String Table 是JVM内部用于管理字符串常量池的数据结构。它是实现字符串常量池的具体形式,通常实现为一个哈希表,用于存储字符串对象的引用。通过String.intern()方法可以手动将字符串添加到String Table中,从而使得这些字符串能够在整个JVM范围内共享。

案例1

public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = "ab";
}

执行javap -v Demo.class
在这里插入图片描述
观察
在这里插入图片描述
常量池中的信息,都会被加载到运行时常量池中, 这时 a、b、ab 都是常量池中的符号,还没有变为java 字符串对象。
当具体执行到指定的代码行时,才会变成java字符串对象(懒加载)。如执行:
在这里插入图片描述
ldc #2 会把 a 符号变为 “a” 字符串对象
ldc #3 会把 b 符号变为 “b” 字符串对象
ldc #4 会把 ab 符号变为 “ab” 字符串对象
当变为字符串对象后,会将如a为key,放入StringTable中(如果没有该key则放入)
StringTable ( “a”, “b” ,“ab” ) 是 hashTable 结构,不能扩容。

案例2

    public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = "ab";String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()  new String("ab")}

执行javap -v Demo.class

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=5, args_size=10: ldc           #2                  // String a2: astore_13: ldc           #3                  // String b5: astore_26: ldc           #4                  // String ab8: astore_39: new           #5                  // class java/lang/StringBuilder 创建StringBuilder对象//new StringBuilder12: dup13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V 调用无参构造方法//new StringBuilder()16: aload_1 //加载s1        17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;//new StringBuilder().append("a")20: aload_221: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;//new StringBuilder().append("a").append("b")24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;//new StringBuilder().append("a").append("b").toString()27: astore        4 //s4字符串存入LocalVariableTable中的4号位置29: return

StringBuilder中的toString方法重新创建了一个新的String字符串

public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
{@Overridepublic String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count);}
}

所以s3不等于s4

public static void main(String[] args) {String s1 = "a"; // 懒惰的String s2 = "b";String s3 = "ab";String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()System.out.println(s3 == s4);//false
}

案例3

    public static void main(String[] args) {String s1 = "a"; // 懒惰的String s2 = "b";String s3 = "ab";String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()  new String("ab")String s5 = "a" + "b";  // javac 在编译期间会进行优化//因为是两个字符串拼接而不是变量,所以结果已经在编译期确定为abSystem.out.println(s3 == s5);//true}

执行javap -v Demo.class

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=3, locals=6, args_size=10: ldc           #2                  // String a2: astore_13: ldc           #3                  // String b5: astore_26: ldc           #4                  // String ab8: astore_39: new           #5                  // class java/lang/StringBuilder12: dup13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V16: aload_117: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;20: aload_221: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;27: astore        429: ldc           #4                  // String ab31: astore        5

在这里插入图片描述

String.intern()

代码示例

public static void main(String[] args) {String s1 = "hello"; // 字面量,存储在字符串常量池String s2 = new String("hello"); // 新对象,存储在堆中String s3 = s2.intern(); // 将 s2 的字符串内容添加到字符串常量池System.out.println(s1 == s2); // false,s1 在字符串常量池,s2 在堆中System.out.println(s1 == s3); // true,s3 是字符串常量池中的引用
}

解析:
String s1 = “hello”;:

  • 字符串 “hello” 存储在字符串常量池中。
  • s1 直接引用字符串常量池中的对象。

String s2 = new String(“hello”);:

  • 新创建的 String 对象存储在堆中。
  • s2 引用堆中的对象。

String s3 = s2.intern();:

  • intern() 方法将 s2 的字符串内容添加到字符串常量池(如果池中已存在,则返回池中的引用)。
  • s3 引用字符串常量池中的对象。

s1 == s3 为 true:

  • 因为 s1 和 s3 都引用字符串常量池中的同一个对象。

案例4

使用intern()将字符串对象尝试放入串池

public static void main(String[] args) {String s = new String("a") + new String("b");//注意:// "a"和"b"是常量,所以会放在串池中// new String("a")和new String("b")会放在堆内存中,// s也一样,因为是两个String对象使用了StringBuilder拼接,所以生成一个新的对象new String("ab")String s2 = s.intern();//将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回System.out.println(s == "ab");//trueSystem.out.println(s2 == "ab");//true
}

案例5

//先将ab放入串池
String x = "ab";
String s = new String("a") + new String("b");
String s2 = s.intern();//因为ab已经在串池中,所以没有放入,直接返回的是串池中的对象
System.out.println(s == x);//false
System.out.println(s2 == x);//true

先调用intern()

String s = new String("a") + new String("b");
String s2 = s.intern();//因为ab已经在串池中,所以没有放入,直接返回的是串池中的对象
String x = "ab";
System.out.println(s == x);//true
System.out.println(s2 == x);//true

案例6

public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = "a" + "b";  //因为是字符串拼接,所以直接变为 "ab"String s4 = s1 + s2;    //因为是两个变量拼接,所以会在运行期间通过StringBuild做字符串拼接,在堆中创建新的对象String s5 = "ab";       //因为常量池中已经有"ab",所以直接引用常量池中的对象String s6 = s4.intern();//因为"ab"已经放入串池,所以s4没有放入串池,而是直接引用常量池中的对象//s3在常量池中,s4在堆中System.out.println(s3 == s4);//falseSystem.out.println(s3 == s5);//trueSystem.out.println(s3 == s6);//trueSystem.out.println("======================");String x2 = new String("c") + new String("d");String x1 = "cd";x2.intern();System.out.println(x1 == x2);//falseSystem.out.println("======================");String y2 = new String("x") + new String("y");y2.intern();String y1 = "xy";System.out.println(y1 == y2);//true
}

总结

  • 常量池中的字符串仅是符号,第一次用到时才变为对象
  • 利用串池的机制,来避免重复创建字符串对象
  • 字符串变量拼接的原理是 StringBuilder (1.8)
  • 字符串常量拼接的原理是编译期优化
  • 可以使用 intern 方法,主动将串池中还没有的字符串对象放入串池
    注意:
    • 1.8 将这个字符串对象尝试放入字符串常量池,如果有则并不会放入,如果没有则把此对象放入串池, 会把串池中的对象返回
    • 1.6 将这个字符串对象尝试放入字符串常量池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回(只会将对象副本放入串池)

StringTable 垃圾回收案例

设置参数
-Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc

/*** 演示 StringTable 垃圾回收* -Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc*/
public class Demo {public static void main(String[] args) throws InterruptedException {int i = 0;try {} catch (Throwable e) {e.printStackTrace();} finally {System.out.println(i);}}
}

打印

0
HeapPSYoungGen      total 2560K, used 1955K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)eden space 2048K, 95% used [0x00000000ffd00000,0x00000000ffee8c18,0x00000000fff00000)from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)ParOldGen       total 7168K, used 0K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)object space 7168K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffd00000)Metaspace       used 3293K, capacity 4564K, committed 4864K, reserved 1056768Kclass space    used 361K, capacity 388K, committed 512K, reserved 1048576K
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     13355 =    320520 bytes, avg  24.000
Number of literals      :     13355 =    594648 bytes, avg  44.526
Total footprint         :           =   1075256 bytes
Average bucket size     :     0.667
Variance of bucket size :     0.668
Std. dev. of bucket size:     0.817
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :     60013 =    480104 bytes, avg   8.000
Number of entries       :      1745 =     41880 bytes, avg  24.000
Number of literals      :      1745 =    177296 bytes, avg 101.602
Total footprint         :           =    699280 bytes
Average bucket size     :     0.029
Variance of bucket size :     0.029
Std. dev. of bucket size:     0.171
Maximum bucket size     :         2

重点观察其中的StringTable statistics

1.创建100个字符串(不会触发垃圾回收)

public class Demo {public static void main(String[] args) throws InterruptedException {int i = 0;try {for (int j = 0; j < 100; j++) { // j=100, j=10000,100000String.valueOf(j).intern();i++;}} catch (Throwable e) {e.printStackTrace();} finally {System.out.println(i);}`}
}

打印

StringTable statistics:
Number of buckets       :     60013 =    480104 bytes, avg   8.000
Number of entries       :      1845 =     44280 bytes, avg  24.000
Number of literals      :      1845 =    182096 bytes, avg  98.697
Total footprint         :           =    706480 bytes
Average bucket size     :     0.031
Variance of bucket size :     0.031
Std. dev. of bucket size:     0.175
Maximum bucket size     :         2

可以发现Number of entries与Number of literals新增了100个字符串对象

2.创建10000个字符串(触发垃圾回收)

[GC (Allocation Failure) [PSYoungGen: 2048K->488K(2560K)] 2048K->786K(9728K), 0.0359746 secs] [Times: user=0.00 sys=0.00, real=0.04 secs] 
10000
HeapPSYoungGen      total 2560K, used 851K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)eden space 2048K, 17% used [0x00000000ffd00000,0x00000000ffd5ac98,0x00000000fff00000)from space 512K, 95% used [0x00000000fff00000,0x00000000fff7a020,0x00000000fff80000)to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen       total 7168K, used 298K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)object space 7168K, 4% used [0x00000000ff600000,0x00000000ff64a8b0,0x00000000ffd00000)Metaspace       used 3296K, capacity 4564K, committed 4864K, reserved 1056768Kclass space    used 361K, capacity 388K, committed 512K, reserved 1048576K
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     13356 =    320544 bytes, avg  24.000
Number of literals      :     13356 =    594664 bytes, avg  44.524
Total footprint         :           =   1075296 bytes
Average bucket size     :     0.667
Variance of bucket size :     0.668
Std. dev. of bucket size:     0.817
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :     60013 =    480104 bytes, avg   8.000
Number of entries       :      8582 =    205968 bytes, avg  24.000
Number of literals      :      8582 =    505552 bytes, avg  58.908
Total footprint         :           =   1191624 bytes
Average bucket size     :     0.143
Variance of bucket size :     0.154
Std. dev. of bucket size:     0.393
Maximum bucket size     :         3

因为创建的字符串对象没有被引用,所以无用的字符串被垃圾回收

StringTable 性能调优

原理:StringTable底层是一个hash表,哈希桶越多,元素越分散,哈希碰撞的几率变小,查找速度会变快

1.调整StringTable哈希桶个数参数:调整 -XX:StringTableSize=桶个数

注意:设置桶个数小于1009时会报错

Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
StringTable size of 200 is invalid; must be between 1009 and 2305843009213693951

设置参数
-Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=200000

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;/*** 演示串池大小对性能的影响* -Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=1009*/
public class Demo {public static void main(String[] args) throws IOException {//linux.words中大约有48万个单词try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {String line = null;long start = System.nanoTime();while (true) {line = reader.readLine();if (line == null) {break;}line.intern();}System.out.println("读取文件花费时间为:" + (System.nanoTime() - start) / 1000000);}}
}

注意:垃圾回收只有在内存紧张时才会触发

打印

读取文件花费时间为:191
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     13359 =    320616 bytes, avg  24.000
Number of literals      :     13359 =    594752 bytes, avg  44.521
Total footprint         :           =   1075456 bytes
Average bucket size     :     0.668
Variance of bucket size :     0.668
Std. dev. of bucket size:     0.818
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :    200000 =   1600000 bytes, avg   8.000
Number of entries       :    481489 =  11555736 bytes, avg  24.000
Number of literals      :    481489 =  29750392 bytes, avg  61.788
Total footprint         :           =  42906128 bytes
Average bucket size     :     2.407
Variance of bucket size :     2.420
Std. dev. of bucket size:     1.556
Maximum bucket size     :        12

设置参数
-Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=1009


读取文件花费时间为:3685
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     15965 =    383160 bytes, avg  24.000
Number of literals      :     15965 =    682432 bytes, avg  42.746
Total footprint         :           =   1225680 bytes
Average bucket size     :     0.798
Variance of bucket size :     0.794
Std. dev. of bucket size:     0.891
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :      1009 =      8072 bytes, avg   8.000
Number of entries       :    482761 =  11586264 bytes, avg  24.000
Number of literals      :    482761 =  29845656 bytes, avg  61.823
Total footprint         :           =  41439992 bytes
Average bucket size     :   478.455
Variance of bucket size :   432.022
Std. dev. of bucket size:    20.785
Maximum bucket size     :       547

可以看到StringTableSize变小后,向StringTable放入字符串的时间明显变长了

2.考虑将字符串对象是否入池

当有大量重复的字符串时,可以考虑使用intern()放入串池,减少字符串对象个数,节约内存

常量池和运行时常量池、字符串常量池三者之间的关系

  • 常量池是.class文件的一部分(每个class文件都有自己独立的常量池),提供了类或接口在编译时所需的各种常量信息。
  • 运行时常量池是JVM方法区中的一部分,当JVM加载一个类文件时,会将该类的常量池信息(常量池表)加载到方法区内的运行时常量池中。
  • 字符串常量池特别针对字符串进行了优化设计,以实现字符串共享,减少内存占用。它是一个类似于哈希表(HashTable)的数据结构,在 HotSpot 虚拟机中由 StringTable 类实现。
  • JDK 1.7之后运行时常量池在方法区中,字符串常量池在堆中。因此在JDK 6及之前,字符串常量池是运行时常量池的一部分,而JDK 7及之后字符串常量池被移到堆中,因此字符串常量池不再是严格意义上的运行时常量池的一部分。
  • 运行时常量池中存储的是字符串常量的引用,而不是字符串对象本身。字符串对象的实际内容存储在堆中的字符串常量池

相关文章:
JVM内存结构笔记01-运行时数据区域
JVM内存结构笔记02-堆
JVM内存结构笔记03-方法区
JVM内存结构笔记04-字符串常量池

相关文章:

JVM内存结构笔记04-字符串常量池

文章目录 定义字符串常量池的位置JDK 1.7 为什么要将字符串常量池移动到堆中&#xff1f; StringTable案例1案例2案例3 String.intern()案例4案例5案例6总结 StringTable 垃圾回收案例1.创建100个字符串(不会触发垃圾回收)2.创建10000个字符串(触发垃圾回收) StringTable 性能调…...

STM32 HAL库实战:高效整合DMA与ADC开发指南

STM32 HAL库实战&#xff1a;高效整合DMA与ADC开发指南 一、DMA与ADC基础介绍 1. DMA&#xff1a;解放CPU的“数据搬运工” DMA&#xff08;Direct Memory Access&#xff09; 是STM32中用于在外设与内存之间直接传输数据的硬件模块。其核心优势在于无需CPU干预&#xff0c;…...

c语言闯算法--常用技巧

双指针 类别&#xff1a; 同向快慢指针 异常情况&#xff0c;慢指针才动 双向指针 视情况&#xff0c;左右指针动 最长无重复子串 int max(int a, int b){if(a < b){return b;}else{return a;} } int lengthOfLongestSubstring(char* s) {int count[300];for(int i 0; i …...

docker启动jenkins,jenkins中调用docker

在jenkins中执行docker 思路 jenkins中安装docker客户端&#xff0c;使用第三方的docker(需要付费)。jenkins中安装docker客户端&#xff0c;另一个容器中安装docker服务&#xff0c; docker-in-docker&#xff0c;需要特权模式&#xff0c;或者第三方的工具。jenkins中什么都…...

【设计模式】设计模式介绍

一、设计模式概述 设计模式分很多种&#xff0c;每种一般都用于解决某个软件开发过程中的问题。许多人认为设 计模式有23种&#xff0c;其实&#xff0c;对于这个数字也没必要那么教条&#xff0c;当然还有更多的设计模式种类&#xff0c;只 不过是这23种比较经典而已。甚至可…...

图形学面试题总结

图形学面试题总结 文章目录 图形学面试题总结Opengl 与 Vulkan1、OpenGL的渲染管线有哪些主要阶段&#xff1f;分别做什么&#xff1f;2、OpenGL中的VAO、VBO和EBO分别是什么&#xff1f;为什么需要它们&#xff1f;3、细分着色器与几何着色器是什么4、Vulkan与Opengl的区别是什…...

Spring Cloud Alibaba 实战:Sentinel 保障微服务的高可用性与流量防护

1.1 Sentinel 作用 Sentinel 是阿里巴巴开源的一款 流量控制和熔断降级 框架&#xff0c;主要用于&#xff1a; 流量控制&#xff1a;限制 QPS&#xff0c;防止流量暴增导致系统崩溃熔断降级&#xff1a;当某个服务不可用时自动降级&#xff0c;避免故障扩散热点参数限流&…...

Comfyui 与 SDwebui

ComfyUI和SD WebUI是基于Stable Diffusion模型的两种不同用户界面工具&#xff0c;它们在功能、用户体验和适用场景上各有优劣。 1. 功能与灵活性 ComfyUI&#xff1a;ComfyUI以其节点式工作流设计为核心&#xff0c;强调用户自定义和灵活性。用户可以通过连接不同的模块&…...

面试之《前端常见的设计模式》

前端开发中运用多种设计模式可以提高代码的可维护性、可扩展性和可复用性。以下是一些常见的前端设计模式&#xff1a; 创建型模式 1. 单例模式 定义&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。应用场景&#xff1a;在前端中&#xff0c;像全局状…...

PostgreSQL异常:An IO error occurred while sending to the backend

在使用PostgreSQL数据库批量写入数据的时候&#xff0c;遇到了一个问题&#xff0c;异常内容如下&#xff1a; Cause: org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.报错内容 报错提示1 Caused by: org.postgresql.util.PSQLExc…...

嵌入式八股C语言---面向对象篇

面向对象与面向过程 面向过程 就是把整个业务逻辑分成多个步骤,每步或每一个功能都可以使用一个函数来实现面向对象 对象是类的实例化,此时一个类就内部有属性和相应的方法 封装 在C语言里实现封装就是实现一个结构体,里面包括的成员变量和函数指针,然后在构造函数中,为结构体…...

一周学会Flask3 Python Web开发-使用SQLAlchemy动态创建数据库表

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们定义了模型&#xff0c;我们可以通过sqlalchemy对象提供的create_all()方法来映射和动态创建数据库表。 因为我们用到…...

【spring】springAOP

1.基本概念 AOP即面向切面编程&#xff0c;它利用的是一种横切技术&#xff0c;解剖开封装的对象内部&#xff0c;并将那些影响多个类的公共行为封装到一个可重 用模块&#xff0c;这就是所谓的Aspect方面/切面。所谓的切面&#xff0c;简单点所说&#xff0c;就是将哪些与业务…...

解决VMware虚拟机CentOS 7 忘记登陆密码问题

1. 重启虚拟机&#xff0c;在重启时不停按E键进入初始化脚本编辑界面 2.在初始化脚本编辑界面&#xff0c;按↓键向下拉到最后&#xff0c;找到LANG/zh_CN.UTF-8那里&#xff0c;输入空格&#xff0c;接着添加 "init/bin/sh" 。然后按ctrlX键进入下一步。 3. 在界面中…...

如何在 Windows 10 启用卓越性能模式及不同电源计划对比

在使用 powercfg -duplicatescheme 命令启用 “卓越性能模式”&#xff08;即 Ultimate Performance 模式&#xff09;之前&#xff0c;有几个前提条件需要注意&#xff1a; 前提条件&#xff1a; 系统版本要求&#xff1a;卓越性能模式 仅在 Windows 10 专业版 或更高版本&a…...

基于 GEE 利用 Sentinel-2 数据反演叶绿素与冠层水分含量

目录 1 数据加载与预处理 2 叶绿素含量反演 3 冠层水分反演 4 数据可视化与导出 5 完整代码 6 运行结果 在生态学和环境科学领域&#xff0c;植被的健康状况是评估生态系统稳定性和功能的关键指标之一。而叶绿素含量和冠层水分含量作为反映植被生理状态的重要参数&#x…...

《鸿蒙系统下AI模型训练加速:时间成本的深度剖析与优化策略》

在当今数字化浪潮中&#xff0c;鸿蒙系统凭借其独特的分布式架构与强大的生态潜力&#xff0c;为人工智能的发展注入了新的活力。随着AI应用在鸿蒙系统上的日益普及&#xff0c;如何有效降低模型训练的时间成本&#xff0c;成为了开发者与研究者们亟待攻克的关键课题。这不仅关…...

PyTorch分布式训练

本文结构&#xff1a; 分布式训练概述环境设置数据并行&#xff08;DDP&#xff09;模型并行启动训练性能优化建议示例代码参考资料和相关问题 以下是为您整理的PyTorch分布式训练教程指南&#xff1a; 一、PyTorch分布式训练核心概念 数据并行&#xff1a;通过分割数据集实…...

ubuntu22.04 关于挂在设备为nfts文件格式无法创建软连接的问题

最近遇到情况&#xff0c;解压工程报错&#xff0c;无法创建软连接 但是盘内还有130G空间&#xff0c;明显不是空间问题&#xff0c;查找之后发现是移动硬盘的文件格式是NTFS&#xff0c;在ubuntu上不好兼容&#xff0c;于是报错。 开贴记录解决方案。 1.确定文件格式 使用命…...

C++编程:进阶阶段—4.2对象

目录 4.2 对象特征 4.2.1 构造函数和析构函数 4.2.2 构造函数的分类 4.2.3 拷贝函数调用时机 4.2.4 构造函数调用规则 4.2.5 深拷贝与浅拷贝 4.2.6 初始化列表 4.2.7 类对象作为类成员 4.2.8 静态成员 4.2.9 成员变量和成员函数的存储 4.2.10 this指针 4.2.11 空指针…...

C++跨平台开发环境搭建全指南:工具链选型与性能优化实战

C跨平台开发环境搭建全指南&#xff1a;工具链选型与性能优化实战 目录 开发环境搭建工具链选型性能优化实战常见问题排查 开发环境搭建 操作系统环境准备 Windows# 安装Visual Studio Build Tools choco install visualstudio2022buildtools choco install cmake --instal…...

常见JVM命令

1. java -XX:PrintCommandLineFlags HelloGC 作用&#xff1a;打印 JVM 启动时的命令行参数&#xff0c;包括用户显式设置的参数和 JVM 自动默认设置的参数。用于确认 JVM 实际使用的配置。 2. java -Xmn10M -Xms40M -Xmx60M -XX:PrintCommandLineFlags -XX:PrintGC -XX:Prin…...

C语言实现队列数据结构:思路与代码详解

目录 一、引言 二、整体思路 三、代码模块分析 &#xff08;一&#xff09;头文件包含与宏定义 &#xff08;二&#xff09;数据类型定义 &#xff08;三&#xff09;队列操作函数 1. 队列初始化 2. 队列销毁 3. 入队操作 4. 出队操作 5. 获取队头元素 6…...

【Docker项目实战】使用Docker与Caddy部署BanBan任务管理工具

【Docker项目实战】使用Docker部署BanBan任务管理工具 一、BanBan介绍1.1 BanBan简介1.2 主要特点1.3 使用场景二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、下载BanBan镜像五、…...

AI重构私域增长:从流量收割到终身价值运营的三阶跃迁

私域运营的AI进化论&#xff1a;内容即服务的三个阶段 随着企业微信生态的成熟&#xff0c;私域运营正经历从"流量收割"到"关系养成"的本质转变。在AIGC技术的推动下&#xff0c;2024年私域场景正式进入**"内容即服务"**的价值共创期&#xff1…...

es扩容节点以后写入数据量增加1倍

背景&#xff1a; es扩容一倍的数据节点以后 写入数据量增加1倍 业务反馈业务访问量没增加。 最后定位是监控数据&#xff1a; PUT _cluster/settings {"persistent": {"xpack.monitoring.collection.enabled" : "false"} }这个索引记录的是 节…...

Go本地缓存设计与实现

本地缓存是一个项目中很常见的组件。在很多人的眼中就是一个简单的key-value的map存储即可实现&#xff0c;但实际上&#xff0c;设计一个本地缓存需要考虑的问题远比你想象的多&#xff0c;比如说&#xff0c;本地缓存是将数据存储在内存&#xff0c;若数据量激增突破了内存限…...

04 | 初始化 fastgo 项目仓库

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入 云原生 AI 实战 星球&#xff0c;12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力&#xff08;聚焦于 Go、云原生、AI Infra&#xff09;&#xff1b;本节课最终…...

Spring中复杂对象的创建方式:FactoryBean、实例工厂与静态工厂全解析

1.反转控制与依赖注入 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring工厂和配置文件中完成 好处&#xff1a;解耦合 底层实现&#xff1a;工厂设计模式 依赖注入&#xff1a; 注入&#xf…...

异或和之和 第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 A 组

异或和之和 题目来源 第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 A 组 原题链接 蓝桥杯 异或和之和 https://www.lanqiao.cn/problems/3507/learning/ 问题描述 问题分析 要点1:异或运算 概念 异或(Exclusive OR,简称 XOR)是一种数学运算符,常用于逻辑运算与计算机…...

设计模式 一、软件设计原则

一、理解设计原则 1、单一原则 1.1 如何理解单一职责原则&#xff08;SRP&#xff09; 单一职责原则&#xff08;Single Responsibility Principle&#xff0c;简称SRP&#xff09;,他要求一个类或模块应该只负责一个特定的功能&#xff0c;这有助于降低类之间的耦合度&#xf…...

修复Electron项目Insecure Content-Security-Policy(内容安全策略CSP)警告的问题

将以下代码粘贴进html的<header>标签内 <metahttp-equiv"Content-Security-Policy"content"default-src self; style-src self unsafe-inline; img-src self data:; "> 解释一下上面代码中的属性含义 default-src self&#xff1a;配置加载策…...

机器人交互系统 部署构建

环境要求 Ubuntu 20.04 或更高版本ROS Noetic 或兼容版本Python 3.8 安装步骤 1. 安装ROS环境&#xff08;如未安装&#xff09; sudo apt update sudo apt install ros-noetic-desktop-full source /opt/ros/noetic/setup.bash2. 创建工作空间并克隆代码 mkdir -p ~/code…...

当AI回答问题时,它的“大脑”里在炒什么菜?

文章目录 1. 拆解订单&#xff1a;AI如何听懂你的“暗号”&#xff1f;2. 调用工具&#xff1a;AI的“万能工具箱”里有什么&#xff1f;3. 知识不够&#xff1f;去“图书馆”现学现卖&#xff01;4. 人类的秘密武器&#xff1a;给AI戴上“镣铐”5. 为什么AI会“胡言乱语”&…...

linux 软件扩展GPU显存

概述 共享内存可以通过 Unified Memory&#xff08;统一内存&#xff09;来实现&#xff0c;它允许 CPU 和 GPU 共享相同的内存地址空间&#xff0c;从而方便数据的传输和访问。 利用该技术可解决家用GPU 机器学习时显存不足的问题 &#xff08;注&#xff1a; 虽然解决了爆显…...

【RabbitMQ】Spring Boot 结合 RabbitMQ 完成应用间的通信

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 Spring 框架与 RabbitMQ 的整合主要通过 Spring AMQP&#xff08;Advanced Message Queuing Protocol&#xff09;模块实现&#xff0c;提供了便捷的消息队列开发能力。 引…...

DeepSeek本地化部署(DeepSeek+olloma+Dify)

文章目录 概要需要准备的工具Ollama准备内容Docker准备内容Dify准备内容本地访问Dify 概要 提示&#xff1a;本篇文章主要讲述如何部署本地Deepseek私有大模型&#xff0c;使用Windows无显卡环境进行部署 需要准备的工具 Ollama、Docker Desktop 下载地址&#xff1a; Ollama…...

Spring boot3-WebClient远程调用非阻塞、响应式HTTP客户端

来吧&#xff0c;会用就行具体理论不讨论 1、首先pom.xml引入webflux依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId> </dependency> 别问为什么因为是响应式....…...

Ubuntu22.04安装数据

数据库安装步骤&#xff1a; sudo apt-get update sudo apt install mysql-server mysql-client sudo systemctl start mysql sudo systemctl status mysql &#xff08;1&#xff09;在命令行登录 MySQL 数据库&#xff0c;并使用 mysql 数据库 &#xff08;必须使用这个…...

【python-uiautomator2】手机上的ATX应用界面报错问题处理:无法提供服务,非am instrument启动

目录 一、前期准备 1.1 插入设备 1.2 安装atx-agent 二、解决报错&#xff1a;无法提供服务&#xff0c;非am instrument启动 2.1 出现报错 2.2 尝试解决 2.3 最终解决 三、开启ATX的悬浮窗权限 一、前期准备 1.1 插入设备 本地插入待执行设备&#xff0c;待执行设备…...

自动化测试介绍及学习路线

目录 一、自动化测试 1.1 自动化测试的概念 1.2 自动化测试的主流领域 接口自动化测试 UI自动化测试 持续集成 二、学习路线 一、自动化测试 1.1 自动化测试的概念 自动化测试是指利用软件工具或脚本来执行测试用例和比较实际结果与预期结果的过程&#xff0c;通过运行…...

Python:函数(一)

python函数相关的知识点 1. 函数定义与调用 定义&#xff1a;使用 def 关键字&#xff0c;后接函数名和参数列表。 def greet(name):"""打印问候语&#xff08;文档字符串&#xff09;"""print(f"Hello, {name}!") 调用&#xff1a…...

qml c++混合编程注意事项

在Qml和C类进行数据交互时&#xff0c;通用的办法都是注册C到Qml中&#xff0c;但是很多时候C的对象是在C中进行创建&#xff0c;如果在Qml中创建了&#xff0c;数据之间的交互就会出现无法控制的问题。 信号与槽、上下文等都是数据交互的方式&#xff0c;但是当嵌套多层时&…...

Leetcode6-Z字形变换

题目链接&#xff1a;6. Z 字形变换 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 定义numRows个字符数组&#xff0c;用于存每一行的字符&#xff1b;再定义一个标志行数的变量cnt&#xff0c;cnt在0到numRows-1之间不停的加一或减一&#xff08;当cnt到0了&am…...

【eNSP实战】配置交换机端口安全

拓扑图 目的&#xff1a;让交换机端口与主机mac绑定&#xff0c;防止私接主机。 主机PC配置不展示&#xff0c;按照图中配置即可。 开始配置之前&#xff0c;使用PC1 ping 一遍PC2、PC3、PC4、PC5&#xff0c;让交换机mac地址表刷新一下记录。 LSW1查看mac地址表 LSW1配置端…...

React.js 基础与进阶教程

React.js 基础与进阶教程 React.js 是由 Facebook 开发的流行前端 JavaScript 库&#xff0c;专为构建用户界面&#xff08;UI&#xff09;设计&#xff0c;尤其适用于单页面应用&#xff08;SPA&#xff09;。它采用组件化开发模式&#xff0c;使 UI 结构更加清晰、可维护性更…...

Docker基础入门(一)

初识Docker 什么是Docker Docker是一个快速交付应用、运行应用的技术&#xff1a; 可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通过一行命令完成&…...

moment.js时间处理库

目录 一、moment().isValid()验证时间是否有效 二、moment().second()获取秒数或者设置秒数 三、moment().day()获取星期或者设置星期 四、moment().add()加法操作 五、moment().subtract()减法操作 六、moment.max()最大值 七、moment.min()最小值 八、克隆时间 一、mo…...

基于hive的电信离线用户的行为分析系统

标题:基于hive的电信离线用户的行为分析系统 内容:1.摘要 随着电信行业的快速发展&#xff0c;用户行为数据呈现出海量、复杂的特点。为了深入了解用户行为模式&#xff0c;提升电信服务质量和精准营销能力&#xff0c;本研究旨在构建基于 Hive 的电信离线用户行为分析系统。通…...

循环神经网络(RNN):时序建模的核心引擎与演进之路

在人工智能处理序列数据的战场上&#xff0c;循环神经网络&#xff08;RNN&#xff09;如同一个能够理解时间的智者。从 2015 年谷歌神经机器翻译系统颠覆传统方法&#xff0c;到 2023 年 ChatGPT 实现对话连续性&#xff0c;这些突破都植根于 RNN 对时序建模的深刻理解。本文将…...