JVM垃圾回收機制深度解析

🗑? JVM垃圾回收機制深度解析


文章目錄

  • 🗑? JVM垃圾回收機制深度解析
    • 🔍 垃圾判定算法
      • 🔢 引用計數法
      • 🌐 可達性分析算法
    • 🔄 垃圾回收算法
      • 🏷? 標記-清除算法
      • 📋 復制算法
      • 🔧 標記-整理算法
      • 🏗? 分代收集算法
    • 🛠? 常見垃圾收集器
      • 🔄 Serial 收集器
      • ? ParNew 收集器
      • 🚀 Parallel 收集器
      • 🔧 CMS 收集器
      • 🌟 G1 收集器
    • ? 垃圾回收調優
      • 🔧 常用 JVM 調優參數
      • 🛠? 調優工具使用:JConsole、VisualVM
        • JConsole
        • VisualVM
    • 🔬 實戰案例分析
      • 案例一:內存泄漏排查
      • 案例二:GC停頓時間過長
      • 案例三:頻繁的Young GC
    • 📊 總結與展望
      • 垃圾回收技術的發展趨勢
      • 最佳實踐總結


🔍 垃圾判定算法

在JVM中,垃圾回收的第一步是確定哪些對象是"垃圾"。JVM主要采用兩種算法來判斷對象是否可以被回收。

🔢 引用計數法

引用計數法是一種直觀的垃圾判定方法,其核心思想是:為每個對象添加一個引用計數器,當有引用指向該對象時計數器加1,引用失效時計數器減1,計數器為0時即可回收

public class ReferenceCountingExample {public Object instance = null;public static void main(String[] args) {ReferenceCountingExample objA = new ReferenceCountingExample();ReferenceCountingExample objB = new ReferenceCountingExample();// 對象之間相互引用objA.instance = objB;objB.instance = objA;// 將objA和objB置為null,斷開外部引用objA = null;objB = null;// 此時objA和objB指向的對象雖然已經不可能再被訪問,// 但由于它們相互引用,引用計數都不為0,導致無法被回收System.gc(); // 觸發垃圾回收}
}

引用計數法的優缺點:

優點缺點
實現簡單,判定效率高無法解決循環引用問題
對象可以很快被回收計數器增減操作帶來額外開銷
內存管理的實時性較高需要額外的空間存儲計數器

💡 注意:雖然引用計數法簡單直觀,但由于無法解決循環引用問題,現代JVM(如HotSpot)并不使用此算法作為主要的垃圾判定方法。

🌐 可達性分析算法

可達性分析算法是現代JVM采用的主要垃圾判定算法,其核心思想是:通過一系列稱為"GC Roots"的根對象作為起始節點集,從這些節點開始,根據引用關系向下搜索,搜索過程所走過的路徑稱為"引用鏈"。如果某個對象到GC Roots之間沒有任何引用鏈相連,則證明此對象是不可能再被使用的,可以被回收

GC Roots
對象B
對象C
對象D
對象E
對象F
對象G
對象H

在Java中,可作為GC Roots的對象包括:

  1. 虛擬機棧(棧幀中的本地變量表)中引用的對象
  2. 方法區中類靜態屬性引用的對象
  3. 方法區中常量引用的對象
  4. 本地方法棧中JNI(Native方法)引用的對象
  5. 活躍線程
public class GCRootsExample {// 靜態屬性引用的對象作為GC Rootsprivate static Object staticObject;// 常量引用的對象作為GC Rootsprivate static final Object CONST_OBJECT = new Object();public void method() {// 虛擬機棧中引用的對象作為GC RootsObject localObject = new Object();// 使用本地方法nativeMethod();}private native void nativeMethod(); // 本地方法棧中引用的對象作為GC Rootspublic static void main(String[] args) {// main方法是一個活躍線程,其中引用的對象作為GC RootsObject mainObject = new Object();// 創建一個不可達對象Object unreachableObject = new Object();unreachableObject = null; // 斷開引用,此對象變為不可達System.gc(); // 觸發垃圾回收}
}

可達性分析算法的優缺點:

優點缺點
能解決循環引用問題需要STW(Stop-The-World),暫停所有用戶線程
判定更加精確實現復雜
被大多數現代JVM采用可能造成較長時間的停頓

💡 注意:可達性分析算法執行時必須保證整個分析過程的一致性,因此需要STW。JVM后續的優化方向之一就是如何減少STW的時間。

🔄 垃圾回收算法

確定了哪些對象需要回收后,接下來就是如何高效地回收這些對象。JVM主要采用以下幾種垃圾回收算法。

🏷? 標記-清除算法

標記-清除(Mark-Sweep)算法是最基礎的垃圾回收算法,分為兩個階段:

  1. 標記階段:標記出所有需要回收的對象
  2. 清除階段:統一回收所有被標記的對象
graph LRsubgraph 標記前A1[對象A] --- B1[對象B] --- C1[對象C] --- D1[對象D] --- E1[對象E]endsubgraph 標記后A2[對象A] --- B2[對象B 標記] --- C2[對象C] --- D2[對象D 標記] --- E2[對象E 標記]endsubgraph 清除后A3[對象A] --- C3[對象C] --- 空1((空閑)) --- 空2((空閑)) --- 空3((空閑))end標記前 --> 標記后 --> 清除后classDef normal fill:#d4f9d4,stroke:#333,stroke-width:1px;classDef marked fill:#f9d4d4,stroke:#333,stroke-width:1px;classDef empty fill:#d4d4f9,stroke:#333,stroke-width:1px;class A1,B1,C1,D1,E1,A2,C2,A3,C3 normal;class B2,D2,E2 marked;class 空1,空2,空3 empty;

標記-清除算法的優缺點:

優點缺點
實現簡單效率不高,標記和清除兩個過程效率都不高
是其他算法的基礎產生大量內存碎片,導致無法分配大對象

📋 復制算法

復制(Copying)算法將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊內存用完了,就將還存活的對象復制到另一塊上面,然后再把已使用過的內存空間一次清理掉。

graph LRsubgraph 復制前subgraph From空間A1[對象A] --- B1[對象B] --- C1[對象C] --- D1[對象D] --- E1[對象E]endsubgraph To空間空1((空閑)) --- 空2((空閑)) --- 空3((空閑)) --- 空4((空閑)) --- 空5((空閑))endendsubgraph 復制后subgraph To空間變為From空間A2[對象A] --- C2[對象C] --- 空6((空閑)) --- 空7((空閑)) --- 空8((空閑))endsubgraph From空間變為To空間空9((空閑)) --- 空10((空閑)) --- 空11((空閑)) --- 空12((空閑)) --- 空13((空閑))endend復制前 --> 復制后                                                                                                                                                                                                                                                                                                                                                  classDef normal fill:#d4f9d4,stroke:#333,stroke-width:1px;classDef empty fill:#d4d4f9,stroke:#333,stroke-width:1px;class A1,B1,C1,D1,E1,A2,C2 normal;class 空1,空2,空3,空4,空5,空6,空7,空8,空9,空10,空11,空12,空13 empty;

復制算法的優缺點:

優點缺點
實現簡單,運行高效內存利用率低,只有一半內存可用
沒有內存碎片對象存活率高時,復制操作開銷大
適合新生代回收需要額外空間做分配擔保

💡 實際應用:HotSpot VM的新生代使用了復制算法的變種 - Eden和Survivor區的比例是8:1:1,每次只有10%的內存會被"浪費"。

🔧 標記-整理算法

標記-整理(Mark-Compact)算法是針對老年代對象存活率高的特點設計的。標記過程與標記-清除算法一樣,但后續步驟不是直接清理,而是讓所有存活的對象都向內存空間一端移動,然后清理掉邊界以外的內存。

graph LRsubgraph 標記前A1[對象A] --- B1[對象B] --- C1[對象C] --- D1[對象D] --- E1[對象E]endsubgraph 標記后A2[對象A] --- B2[對象B 標記] --- C2[對象C] --- D2[對象D 標記] --- E2[對象E 標記]endsubgraph 整理后A3[對象A] --- C3[對象C] --- 空1((空閑)) --- 空2((空閑)) --- 空3((空閑))end標記前 --> 標記后 --> 整理后classDef normal fill:#d4f9d4,stroke:#333,stroke-width:1px;classDef marked fill:#f9d4d4,stroke:#333,stroke-width:1px;classDef empty fill:#d4d4f9,stroke:#333,stroke-width:1px;class A1,B1,C1,D1,E1,A2,C2,A3,C3 normal;class B2,D2,E2 marked;class 空1,空2,空3 empty;

標記-整理算法的優缺點:

優點缺點
不會產生內存碎片移動對象需要更新引用,效率較低
內存利用率高需要STW,停頓時間可能較長
適合老年代回收實現復雜

🏗? 分代收集算法

分代收集算法并不是一種具體的垃圾回收算法,而是根據對象的生命周期特征,將內存劃分為幾個區域,并在不同區域采用不同的收集算法。

graph TDsubgraph JVM堆內存subgraph 新生代E[Eden區] --- S1[Survivor 1區]E --- S2[Survivor 2區]endsubgraph 老年代O[Old區]endend新生代 -.-> |對象晉升| 老年代classDef eden fill:#f9d4d4,stroke:#333,stroke-width:1px;classDef survivor fill:#d4f9d4,stroke:#333,stroke-width:1px;classDef old fill:#d4d4f9,stroke:#333,stroke-width:1px;class E eden;class S1,S2 survivor;class O old;

分代收集的策略:

  1. 新生代:大多數對象朝生夕滅,存活率低,采用復制算法
  2. 老年代:對象存活率高,采用標記-清除或標記-整理算法

分代收集的對象晉升過程:

public class GenerationalGCExample {public static void main(String[] args) {// 1. 新對象優先在Eden區分配byte[] allocation1 = new byte[30900*1024];// 2. Eden區滿,觸發Minor GC,存活對象復制到Survivor區byte[] allocation2 = new byte[900*1024];// 3. 多次GC后,對象年齡達到閾值,晉升到老年代for (int i = 0; i < 15; i++) {byte[] allocation3 = new byte[1000*1024];allocation3 = null; // 使對象變為垃圾System.gc(); // 建議JVM進行垃圾回收}// 4. 大對象直接進入老年代byte[] allocation4 = new byte[10*1024*1024];}
}

分代收集算法的優缺點:

優點缺點
針對不同代的特點采用最合適的算法實現復雜
提高了垃圾回收效率需要維護多個內存區域
減少了內存碎片和停頓時間各代之間的對象引用需要特殊處理

🛠? 常見垃圾收集器

JVM提供了多種垃圾收集器,每種收集器都有其特點和適用場景。

🔄 Serial 收集器

Serial收集器是最基本、歷史最悠久的垃圾收集器,它是一個單線程收集器,在進行垃圾收集時,必須暫停所有用戶線程。

用戶線程Serial收集器線程運行等待觸發GCSTW開始暫停垃圾收集完成GCSTW結束恢復運行等待用戶線程Serial收集器線程

Serial收集器的特點:

  • 單線程收集
  • 簡單高效,對于單CPU環境來說是首選
  • 收集過程中需要STW,停頓時間較長
  • 新生代采用復制算法,老年代采用標記-整理算法
  • 適用于客戶端應用,如桌面應用程序

啟用參數: -XX:+UseSerialGC

? ParNew 收集器

ParNew收集器是Serial收集器的多線程版本,除了使用多線程進行垃圾收集外,其余行為和Serial收集器完全一樣。

用戶線程ParNew收集器線程1ParNew收集器線程2ParNew收集器線程n運行等待等待等待觸發GCSTW開始暫停垃圾收集垃圾收集垃圾收集完成GCSTW結束恢復運行等待等待等待用戶線程ParNew收集器線程1ParNew收集器線程2ParNew收集器線程n

ParNew收集器的特點:

  • 多線程收集,充分利用多核CPU優勢
  • 收集過程中需要STW,但停頓時間比Serial短
  • 新生代采用復制算法
  • 是許多服務端應用首選的新生代收集器
  • 可與CMS收集器配合使用

啟用參數: -XX:+UseParNewGC

🚀 Parallel 收集器

Parallel收集器(也稱為Parallel Scavenge收集器)是一個新生代收集器,使用復制算法,也是并行的多線程收集器。

public class ParallelGCExample {public static void main(String[] args) {// 設置Parallel收集器參數// -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:GCTimeRatio=19// 創建大量對象觸發GCList<byte[]> list = new ArrayList<>();for (int i = 0; i < 1000; i++) {byte[] bytes = new byte[1024 * 1024]; // 1MBlist.add(bytes);if (i % 10 == 0) {list.clear(); // 釋放引用,觸發GC}}}
}

Parallel收集器的特點:

  • 多線程收集,注重吞吐量
  • 可設置最大垃圾收集停頓時間和吞吐量
  • 自適應調節策略,動態調整參數
  • 新生代采用復制算法,老年代采用標記-整理算法
  • 適用于后臺運算而不需要太多交互的應用

啟用參數:

  • -XX:+UseParallelGC:新生代使用Parallel Scavenge,老年代使用Serial Old
  • -XX:+UseParallelOldGC:新生代使用Parallel Scavenge,老年代使用Parallel Old

🔧 CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器,它非常適合互聯網站或者B/S系統的服務端,這類應用通常重視服務的響應速度,希望系統停頓時間最短。

用戶線程CMS收集器線程運行等待觸發GC初始標記(STW)短暫暫停標記GC Roots并發標記繼續運行并發標記存活對象重新標記(STW)短暫暫停修正標記結果并發清除繼續運行并發清除垃圾對象完成GC運行等待用戶線程CMS收集器線程

CMS收集器的工作流程:

  1. 初始標記:標記GC Roots能直接關聯到的對象,速度很快,需要STW
  2. 并發標記:進行GC Roots Tracing,與用戶線程并發執行
  3. 重新標記:修正并發標記期間因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記記錄,需要STW
  4. 并發清除:清除標記為垃圾的對象,與用戶線程并發執行

CMS收集器的特點:

  • 并發收集,低停頓
  • 采用標記-清除算法,會產生內存碎片
  • 對CPU資源敏感
  • 無法處理浮動垃圾(并發清除階段產生的垃圾)
  • 需要預留一部分內存作為并發收集時的預留空間

啟用參數: -XX:+UseConcMarkSweepGC

🌟 G1 收集器

G1(Garbage-First)收集器是一款面向服務端應用的垃圾收集器,它是JDK 9的默認垃圾收集器。G1收集器的設計目標是取代CMS收集器,它同樣具有并發和并行、低停頓的特點,同時兼顧了高吞吐量。

G1堆內存
Region 2: Eden
Region 1: Eden
Region 3: Survivor
Region 4: Old
Region 5: Old
Region 6: Humongous
Region 7: Eden
Region 8: Old

G1收集器的工作原理:

  1. 將整個Java堆劃分為多個大小相等的獨立區域(Region)
  2. 保留分代概念,但不再是物理隔離
  3. 建立可預測的停頓時間模型
  4. 采用"標記-整理"算法,降低內存碎片
  5. 采用"復制"算法,提高回收效率
public class G1GCExample {public static void main(String[] args) {// 設置G1收集器參數// -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=2m// 創建大量對象觸發GCList<byte[]> list = new ArrayList<>();Random random = new Random();while (true) {int size = random.nextInt(1024 * 1024); // 0-1MBbyte[] bytes = new byte[size];list.add(bytes);if (list.size() > 10000) {list.subList(0, 5000).clear(); // 釋放一部分引用System.gc(); // 建議JVM進行垃圾回收}try {Thread.sleep(1); // 控制速度} catch (InterruptedException e) {e.printStackTrace();}}}
}

G1收集器的特點:

  • 并發與并行收集
  • 分代收集
  • 空間整合(標記-整理+復制算法,無內存碎片)
  • 可預測的停頓時間模型
  • 適用于大內存、多核CPU的服務器環境

啟用參數: -XX:+UseG1GC

? 垃圾回收調優

垃圾回收調優是JVM性能優化的重要部分,合理的GC參數配置可以顯著提升應用性能。

🔧 常用 JVM 調優參數

參數說明示例值
-Xms初始堆大小-Xms4g
-Xmx最大堆大小-Xmx4g
-Xmn新生代大小-Xmn1g
-XX:SurvivorRatioEden區與Survivor區的比例-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold對象晉升老年代的年齡閾值-XX:MaxTenuringThreshold=15
-XX:ParallelGCThreads并行GC線程數-XX:ParallelGCThreads=4
-XX:ConcGCThreads并發GC線程數-XX:ConcGCThreads=2
-XX:InitiatingHeapOccupancyPercent觸發并發GC的堆占用率閾值-XX:InitiatingHeapOccupancyPercent=45
-XX:MaxGCPauseMillis最大GC停頓時間-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSizeG1收集器的Region大小-XX:G1HeapRegionSize=4m

不同場景的JVM參數配置示例:

  1. 高吞吐量場景(后臺批處理):
java -Xms4g -Xmx4g -Xmn1g -XX:+UseParallelGC -XX:ParallelGCThreads=8 -XX:+UseNUMA -jar app.jar
  1. 低延遲場景(交互式應用):
java -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=45 -jar app.jar
  1. 內存受限場景(嵌入式或容器環境):
java -Xms256m -Xmx512m -XX:+UseSerialGC -jar app.jar

🛠? 調優工具使用:JConsole、VisualVM

JConsole

JConsole是JDK自帶的圖形化監控工具,可以監控本地和遠程的Java應用程序。

使用步驟:

  1. 啟動JConsole:在命令行中輸入jconsole
  2. 選擇要監控的Java進程
  3. 查看內存、線程、類、VM摘要等信息

JConsole監控內存的關鍵指標:

  • 堆內存使用情況
  • 非堆內存使用情況
  • 各代內存使用情況
  • GC次數和時間
VisualVM

VisualVM是一個功能更強大的監控和分析工具,它集成了多種JDK命令行工具的功能。

使用步驟:

  1. 啟動VisualVM:在命令行中輸入jvisualvm
  2. 選擇要監控的Java進程
  3. 查看概述、監視、線程、抽樣器、分析器等信息

VisualVM的主要功能:

  • 監控CPU、堆內存、類、線程
  • 執行堆轉儲和線程轉儲
  • 分析性能熱點
  • 安裝插件擴展功能
public class GCTuningExample {public static void main(String[] args) {// 啟動參數: -Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=50 -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStampsSystem.out.println("GC調優示例啟動,進程ID: " + ManagementFactory.getRuntimeMXBean().getName());System.out.println("使用JConsole或VisualVM連接此進程進行監控");List<byte[]> list = new ArrayList<>();int count = 0;try {while (true) {// 創建1MB的對象byte[] bytes = new byte[1024 * 1024];list.add(bytes);count++;if (count % 10 == 0) {// 每創建10個對象,清理一半對象int half = list.size() / 2;list.subList(0, half).clear();System.out.println("已創建對象數: " + count + ", 當前列表大小: " + list.size());}Thread.sleep(100); // 控制速度}} catch (InterruptedException e) {e.printStackTrace();}}
}

🔬 實戰案例分析

案例一:內存泄漏排查

問題描述:一個Web應用在運行一段時間后,內存占用持續增加,最終導致OutOfMemoryError。

排查步驟

  1. 收集證據:使用-XX:+HeapDumpOnOutOfMemoryError參數獲取堆轉儲文件
  2. 分析堆轉儲:使用MAT(Memory Analyzer Tool)分析堆轉儲文件
  3. 定位問題:發現大量的Session對象未被釋放
  4. 解決方案:修復Session管理代碼,確保不再使用的Session被及時釋放
public class MemoryLeakExample {// 問題代碼:使用靜態集合存儲對象,導致內存泄漏private static final Map<String, Object> cache = new HashMap<>();public void addToCache(String key, Object value) {cache.put(key, value); // 對象被添加后永遠不會被移除}// 修復后的代碼:使用WeakHashMap或添加過期機制private static final Map<String, Object> fixedCache = new WeakHashMap<>();public void addToFixedCache(String key, Object value) {fixedCache.put(key, value); // 當key不再被引用時,對應的entry會被自動移除}
}

案例二:GC停頓時間過長

問題描述:一個交易系統在高峰期出現間歇性響應緩慢,監控發現是GC停頓時間過長導致的。

排查步驟

  1. 收集GC日志:使用-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log參數
  2. 分析GC日志:使用GCViewer等工具分析GC日志
  3. 定位問題:發現Full GC頻繁發生,停頓時間長
  4. 解決方案:從Serial Old收集器切換到G1收集器,并調整參數

優化前的JVM參數

-Xms2g -Xmx2g -XX:+UseParallelGC

優化后的JVM參數

-Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=45

案例三:頻繁的Young GC

問題描述:一個數據處理應用頻繁出現Young GC,影響整體吞吐量。

排查步驟

  1. 監控GC活動:使用VisualVM觀察GC頻率和內存使用情況
  2. 分析對象分配:使用-XX:+PrintTenuringDistribution參數查看對象年齡分布
  3. 定位問題:發現大量短生命周期的小對象被頻繁創建
  4. 解決方案:優化代碼,減少對象創建,增加對象復用
public class FrequentYoungGCExample {// 問題代碼:在循環中頻繁創建對象public void processData(List<String> data) {for (String item : data) {// 每次迭代都創建新的StringBuilderStringBuilder builder = new StringBuilder();builder.append("Processing: ").append(item);System.out.println(builder.toString());}}// 優化后的代碼:復用StringBuilder對象public void processDataOptimized(List<String> data) {StringBuilder builder = new StringBuilder();for (String item : data) {builder.setLength(0); // 清空StringBuilderbuilder.append("Processing: ").append(item);System.out.println(builder.toString());}}
}

📊 總結與展望

垃圾回收技術的發展趨勢

  1. 低延遲垃圾收集器:如ZGC(Z Garbage Collector)和Shenandoah,它們的目標是將GC停頓時間控制在10ms以內,無論堆的大小如何

  2. 并發收集的改進:減少或消除STW時間,提高并發收集效率

  3. 自適應調優:更智能的GC參數自動調整,減少人工干預

  4. 大內存優化:針對TB級別內存的優化,支持超大堆

  5. 非易失性內存支持:利用新型存儲技術,如Intel的Optane持久內存

最佳實踐總結

  1. 選擇合適的垃圾收集器

    • 吞吐量優先:Parallel收集器
    • 響應時間優先:CMS或G1收集器
    • 大內存低延遲:ZGC或Shenandoah收集器
  2. 合理設置內存大小

    • 避免設置過大的堆內存,增加GC壓力
    • 避免設置過小的堆內存,導致頻繁GC
    • 新生代與老年代的比例通常為1:2或1:3
  3. 優化對象生命周期

    • 減少臨時對象的創建
    • 使用對象池復用對象
    • 注意集合類的使用,避免內存泄漏
  4. 監控與分析

    • 定期檢查GC日志和內存使用情況
    • 使用專業工具分析性能瓶頸
    • 建立性能基準,及時發現異常

如果這篇博客對你有幫助,不要忘記點贊、收藏和分享哦!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/87908.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/87908.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/87908.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker:容器化技術的基石與實踐指南

在現代軟件開發和部署中&#xff0c;Docker 作為一種領先的容器化平臺&#xff0c;已經成為了開發人員和運維工程師不可或缺的工具。它不僅簡化了應用的部署過程&#xff0c;還提高了應用的可移植性和可擴展性。本文將深入探討 Docker 的核心概念、基本操作以及如何在實際項目中…

java web7(黑馬)

Filter簡介概念: Filter 表示過濾器&#xff0c;是 JavaWeb 三大組件(Servlet、Filter、Listener)之一。過濾器可以把對資源的請求攔截下來&#xff0c;從而實現一些特殊的功能。過濾器一般完成一些通用的操作&#xff0c;比如:權限控制、統一編碼處理、敏感字符處理等等.快速入…

React-forwardRef-useImperativeHandle

forwardRef 暴露dom節點作用&#xff1a;使用ref暴露DOM節點給父組件案例例如在父組件中想要獲取子組件input的輸入值&#xff0c;和讓input獲取焦點父組件import { Button } from antd-mobile import Son from "./components/son"; import { useState,useRef } fro…

Unity 用AI自動開發游戲----Cursor研究(實現一套利用Cursor生成模板快速實現原型的框架)

Unity 快速原型開發框架&#xff08;基于 Cursor AI&#xff09; &#x1f9e9; 框架簡介 本框架結合了 AI 編程助手 Cursor 的代碼生成能力&#xff0c;構建出一套適用于 Unity 項目的模塊化原型開發架構。它旨在極大提升開發效率、降低試錯成本&#xff0c;特別適用于快速搭…

D觸發器實現2分頻verilog及電路

使用D觸發器完成2分頻電路即通過時鐘的上升沿或下降沿到來時進行翻轉得到&#xff0c;信號的兩個狀態所占時間長度相同&#xff0c;因此它的輸出時鐘的占空比為50%。 D觸發器實現2分頻的電路圖如下所示&#xff1a;通過將D觸發器2分頻電路級聯&#xff0c;可實現輸入時鐘的2N倍…

UniApp完美對接RuoYi框架開發企業級應用

UniApp完美對接RuoYi框架的完整方案及可開發系統類型&#xff0c;結合企業級實踐與開源項目經驗整理而成&#xff0c;涵蓋技術對接、系統設計及實戰案例。 &#x1f527; 一、UniApp與RuoYi對接全流程 1. 后端配置&#xff08;RuoYi-Vue/RuoYi-Cloud&#xff09; 跨域支持 在網…

【通識】深度學習理論基礎

1. 深度學習導論 導論和簡介的基礎知識和路徑。 深度學習的各項涵蓋范圍&#xff1a;深度學習MLPs&#xff0c;然后是機器學習、邏輯回歸&#xff0c;知識基礎等等 1&#xff09;連結神經網絡等等&#xff1a;Cybernetics控制論&#xff0c;Connectionism連結主義&#xff0…

sql-labs(11-12)-萬能密碼登錄

sql-labs(11-12)萬能密碼登錄 第十一關&#xff1a; 這關是一個登陸口&#xff0c;也是一個sql注入的漏洞&#xff0c;也就是常說的萬能密碼。 在輸入框賬號密碼種分別輸入 1’ 和1’ 頁面會報錯。后臺使用的單引符號進行的拼接。賬號輸入1’ or ‘1’‘1 密碼輸入 1’ or …

MsSql 其他(2)

???????????????Mysql中的MVCC 一、MVCC 的核心目標與設計背景 MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并發控制&#xff09; 是 InnoDB 存儲引擎為實現高并發事務處理而設計的核心機制。其核心目標是&#xff1a;在不犧牲事務隔…

解決本地部署n8n,域名訪問為什么一直有connection lost的報錯

問題&#xff1a;本地部署的n8n服務用IP訪問一切都正常&#xff0c;但是使用域名后報錯connection lost思路&#xff1a;首先懷疑是ngnix配置問題或者是docker中的環境問題查看docker logsOrigin header does NOT match the expected origin. (Origin: "nxxx.online:1181&…

傳統架構開發VS PREEvision:一場效率與可靠性的降維打擊

當前&#xff0c;整車功能數量激增&#xff0c;意味著需要更龐大的整車數據庫、更復雜的硬件傳感器與執行器網絡、更密集的跨系統交互接口以及更難以預測的耦合效應。這樣一來&#xff0c;單一功能的微小改動&#xff0c;可能會因復雜的依賴關系而引發意想不到的連鎖反應&#…

深度學習基礎1

一、張量 張量其實就是數組&#xff0c;不過是在深度學習中是這樣的叫法 1.張量的創建 &#xff08;1&#xff09;基本創建方式 torch.tensor()&#xff1a;根據指定數據創建張量 import torch import numpy as np """創建張量標量""" data to…

力扣網編程274題:H指數之普通解法(中等)

一. 簡介 本文記錄力扣網上涉及數組&#xff0c;排序方面的編程題&#xff1a;H指數。 二. 力扣網編程274題&#xff1a;H指數&#xff08;中等&#xff09; 給你一個整數數組 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇論文被引用的次數。計算并返回該研…

iptables防火墻,多IP環境下, 指定某個目的IP地址通過某個本地IP訪問,策略路由!

需求在CentOS 7.9中&#xff0c;若需從特定源IP&#xff08;10.0.0.3&#xff09;訪問目標網段 1.1.1.0/24方法一&#xff1a;策略路由&#xff08;支持網段&#xff09;1. 創建自定義路由表# 添加名為custom_table的路由表&#xff08;ID200&#xff09; echo "200 custo…

數字孿生技術引領UI前端設計新趨勢:數據可視化與交互設計的深度融合

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩!一、引言&#xff1a;數字孿生驅動 UI 設計的范式革新在大數據與三維可視化技術爆發的今天&…

【機器學習筆記 Ⅱ】6 激活函數

激活函數是神經網絡的核心組件&#xff0c;其作用遠不止“引入非線性”。以下是系統化的解析&#xff1a;1. 核心作用 (1) 引入非線性沒有激活函數&#xff1a;多層神經網絡等價于單層線性變換&#xff08;矩陣連乘仍是線性&#xff09;。加入激活函數&#xff1a;每層通過非線…

AI無標記動捕如何結合VR大空間技術打造沉浸式游戲體驗

隨著數字科技的迅猛發展&#xff0c;VR大空間技術正逐步成為各行業探索沉浸式體驗的重要方向。在VR游戲領域&#xff0c;市場對于高度沉浸式體驗的需求日益增長&#xff0c;而傳統VR游戲主要依賴手柄和基礎體感進行交互&#xff0c;而在VR大空間中&#xff0c;用戶可以通過全身…

Qt智能指針

在 Qt 框架中&#xff0c;智能指針用于自動管理對象的生命周期&#xff0c;防止內存泄漏。以下是 Qt 中主要的智能指針及其用法詳解&#xff1a;1. QScopedPointer作用&#xff1a;獨占所有權&#xff0c;超出作用域時自動釋放對象&#xff08;類似 std::unique_ptr&#xff09…

408第三季part2 - 計算機網絡 - 信道利用率

理解t1是發送幀的傳輸時間t2是確認幀的傳輸時間中間是傳播過程這整個過程就是發送周期任何題目會有以下幾種情況題目這里數據幀和確認幀長度是一樣的t1 t2然后把t1的傳輸數據算出來然后傳播是0.2sd停止等待 k1確認幀忽略t2 0t1算好后&#xff0c;求數據幀的長度下面是速率&…

Android framework 開發者模式下,如何修改動畫過度模式

Android framework 開發者模式下&#xff0c; 如何修改動畫過度模式 開發者模式下&#xff0c;動畫過度 模式1.0→0.5&#xff0c;按如下方式修改。 開發云 - 一站式云服務平臺 .../core/java/com/android/server/wm/WindowManagerService.java | 8 ---- 1 file changed, …