JVM之虛擬機運行

虛擬機運行快速復習

try-catch:catch-異常表+棧展開,finally-代碼復制+異常表兜底

類的生命周期:加載,連接(驗證,準備,解析),初始化,使用,卸載

類加載器:加載字節碼.Class到JVM中生成一個Class對象

大部分類在具體用到的時候才會去加載(懶加載機制),已經加載的類會被放在 ClassLoader

對于一個類加載器來說,相同二進制名稱的類只會被加載一次

類加載過程:

加載:通過類的全限定名獲取該類的二進制字節流,存到類常量池,內存中生成Class對象

連接:

  1. 驗證:驗證Class二進制字節流合規
  2. 準備:為類對象分配內存
  3. 解析:符號引用轉為直接引用

初始化:執行初始化方法

對象創建過程:類加載檢查+分配內存+初始化零值+設置對象頭+執行對象初始化方法

類加載器:

啟動類加載器|
拓展類加載器|
應用程序類加載器|
自定義類加載器

因為啟動類加載器是C++做的,所以獲取到ClassLoader為NULL的時候就是啟動類加載器

自定義類加載器:

需要繼承 ClassLoader抽象類

不打破雙親委派機制:重寫 ClassLoader 類中的 findClass()

打破雙親委派機制:重寫 loadClass() 方法

類卸載:類無用的時候卸載

無用的類:所有實例被回收,類加載器被回收,Class對象沒有任何引用

雙親委派機制:從下往上判斷類是否被加載,從上往下嘗試加載類

JVM 判定兩個 Java 類是否相同的具體規則:全限定類名+類加載器

為什么要用雙親委派機制:可以避免類被重復加載,同時保證我們的核心API不被修改

如何實現熱部署:自定義類加載器,并重寫 ClassLoader 的 loadClass() ?法

熱部署三步:

1)銷毀原來的?定義 ClassLoader

2)更新 class 類?件

3)創建新的 ClassLoader 去加載更新后的 class 類?件


try-catch在jvm層面是怎么做的?

java中的try-catch通過異常表棧展開來實現

異常表(exception-table)

每個方法的字節碼中都有一個異常表,用于記錄try-catch塊的作用范圍對應的異常處理邏輯

異常表的每個條目包含以下信息:

起點,終點,處理代碼的位置,捕獲異常的類型

起點(start_pc):try塊的起始指令偏移量

終點(end_pc):try塊的結束指令偏移量(不包含該指令)

處理代碼位置(handler_pc):catch塊的第一條指令偏移量

捕獲的異常類型(catch_type):要捕獲的異常類(如java/lang/Exception),若為0表示捕獲所有異常(finally塊)

字節碼結構

Exception table:start  end  handler  type0      10   13       java/io/IOException0      10   20       java/lang/Exception

異常處理流程

拋出異常,從異常表判斷異常是否在處理邏輯內(也就是是否被try-catch{}包圍),

代碼中拋出異常時,JVM會執行以下步驟:

創建異常對象:實例化拋出的異常(如new IOException()

查找異常表:從當前方法的異常表中,按順序匹配以下條件:

異常拋出的位置是否在某個條目的[start_pc, end_pc)范圍內。

拋出的異常是否是catch_type的子類(或自身)

跳轉到處理代碼

若找到匹配條目,跳轉到handler_pc執行catch

若未找到,觸發棧展開:彈出當前棧幀,回到調用者方法重復上述過程。棧展開確保異常沿調用鏈向上傳播,直到被處理或終止線程

未捕獲異常:若所有棧幀均未處理異常,線程終止并打印堆棧跟蹤


finally塊的實現

finally 塊的核心是:無論 try 或 catch 塊中是否拋出異常或提前返回,finally 中的代碼必須執行

為了實現這一點,JVM 的編譯器(如 javac)在生成字節碼時,會通過兩種機制來確保 finally 的執行

finally塊通過兩種方式實現:

代碼復制:編譯器將finally代碼復制到trycatch塊的所有退出路徑(包括return或異常拋出之后)。

異常表條目兜底:若finally需要處理異常退出,會生成一個catch_type=0的條目,捕獲所有異常并執行finally代碼,之后重新拋出異常


代碼復制

編譯器會將 finally 塊中的代碼復制到所有可能的退出路徑,包括:

try 塊正常結束后的退出路徑。

catch 塊處理完異常后的退出路徑。

try 或 catch 塊中的 return、break、continue 語句之前

java代碼

public void example() {try {System.out.println("try");} catch (Exception e) {System.out.println("catch");} finally {System.out.println("finally");}
}

編譯后的字節碼邏輯

// try 塊
L0:System.out.println("try");// 復制 finally 代碼到 try 塊末尾System.out.println("finally");return;// catch 塊
L1:System.out.println("catch");// 復制 finally 代碼到 catch 塊末尾System.out.println("finally");return;// 異常表條目(自動處理異常后的 finally)
Exception table:start=L0, end=L0, handler=L1, type=Exception

關鍵點:

finally 的代碼會被復制到 try 和 catch 的末尾,確保正常流程下一定會執行

如果 try 或 catch 中有 return,編譯器會先執行 finally 代碼,再執行 return


異常表兜底(處理未捕獲的異常)

如果 try 或 catch 塊中拋出了未被捕獲的異常,或者有 throw 語句,JVM 會通過異常表跳轉到 finally 代碼,執行后再重新拋出異常。

異常表條目

編譯器會生成一個特殊的異常表條目用于捕獲所有類型的異常(catch_type=0)

確保任何未處理的異常都會先執行 finally,再繼續傳播異常

java代碼

public void example() {try {throw new IOException();} finally {System.out.println("finally");}
}

字節碼的異常表會生成如下頭目

Exception table:start=L0, end=L1, handler=L2, type=0  // type=0 表示捕獲所有異常

對應的執行流程:

  1. try 塊拋出 IOException
  2. JVM 查找異常表,發現 type=0 的條目(匹配所有異常)。
  3. 跳轉到 handler=L2finally 代碼的位置)執行 System.out.println("finally")
  4. 重新拋出異常,繼續棧展開

假設代碼中有 try 和 finally,但沒有 catch:

try {throw new Exception();
} finally {System.out.println("finally");
}

執行步驟:

  1. try 塊拋出異常,JVM 創建異常對象。
  2. 直接查找當前方法的異常表,找到 catch_type=0 的條目,跳轉到 finally 代碼。
  3. 執行 finally 塊中的代碼。
  4. 重新拋出異常,由外層調用者處理

簡單總結

異常處理:異常表+棧展開

每個方法的字節碼中都有一個異常表,用于記錄try-catch塊的作用范圍對應的異常處理邏輯

記錄

try的起點

try的終點

catch的位置(處理代碼的位置)

捕獲的異常類型

當出現異常的時候查找異常表,查看異常出現的位置,如果有try-catch,就跳轉到catch進行處理

沒有的話就進行棧展開,棧展開確保異常沿調用鏈向上傳播,直到被處理或終止線程

finally塊通過代碼復制和異常表兜底,保證finally塊必須執行

代碼復制:

編譯器將finally代碼復制到trycatch塊的所有退出路徑(包括return或異常拋出之后)

異常表兜底:

如果 try 或 catch 塊中拋出了未被捕獲的異常,或者有 throw 語句,JVM 會通過異常表跳轉到 finally 代碼,執行后再重新拋出異常

編譯器會生成一個特殊的異常表條目用于捕獲所有類型的異常(catch_type=0)

確保任何未處理的異常都會先執行 finally,再繼續傳播異常


能說一下類的生命周期嗎

?個類從被加載到虛擬機內存中開始,到從內存中卸載,整個?命周期需要經過七個階段

加載 (Loading)

連接:{

驗證(Verification)、

準備(Preparation)、

解析(Resolution)、

}

初始化 (Initialization)

使?(Using)

卸載(Unloading)


什么是類加載器

類加載器是一個負責加載類的對象,用于實現類加載過程中的加載這一步
1.每個 Java 類都有一個引用指向加載它的 ClassLoader
2.數組類不是通過 ClassLoader 創建的(數組類沒有對應的二進制字節流),是由 JVM 直接生成

簡單來說,類加載器的主要作用就是加載 Java 類的字節碼( .class 文件)到 JVM 中(在內存中生成一個代表該類的 Class 對象)

字節碼可以是 Java 源程序(.java文件)經過 javac 編譯得來,也可以是通過工具動態生成或者通過網絡下載得來
其實除了加載類之外,類加載器還可以加載 Java 應用所需的資源如文本、圖像、配置文件、視頻等等文件資源。本文只討論其核心功能:加載類


類加載器是動態加載還是靜態加載

JVM 啟動的時候,并不會一次性加載所有的類,而是根據需要去動態加載

也就是說,大部分類在具體用到的時候才會去加載(懶加載機制),這樣對內存更加友好

對于已經加載的類會被放在 ClassLoader

在類加載的時候,系統會首先判斷當前類是否被加載過,已經被加載的類會直接返回,否則才會嘗試加載

也就是說,對于一個類加載器來說,相同二進制名稱的類只會被加載一次


類加載的過程知道嗎

?

加載是 JVM 加載的起點,具體什么時候開始加載,《Java 虛擬機規范》中并沒有進?強制約束,可以交給虛擬機 的具體實現來?由把握。

類加載過程:加載,連接{驗證,準備,解析},初始化


加載

加載過程JVM 要做三件事情:

1)通過?個類的全限定名來獲取定義此類的?進制字節流

2)將這個字節流所代表的靜態存儲結構轉化為方法區(因為包含類常量池)的運行時數據結構

3)在內存中?成?個代表這個類的 java.lang.Class 對象,作為?法區這個類的各種數據的訪問入口

加載階段結束后,Java 虛擬機外部的?進制字節流就按照虛擬機所設定的格式存儲在?法區之中了,?法區中的數據存儲格式完全由虛擬機實現??定義,《Java 虛擬機規范》未規定此區域的具體數據結構。

類型數據妥善安置在?法區之后,會在 Java 堆內存中實例化?個 java.lang.Class 類的對象, 這個對象將作為程序訪問?法區中的類型數據的外部接口


連接

驗證(驗證合法)

驗證是連接階段的第一步,這一階段的目的是確保 Class 文件的字節流中包含的信息符合《Java 虛擬機規范》的全部約束要求,保證這些信息被當作代碼運行后不會危害虛擬機自身的安全


準備(分配內存)

準備階段是正式為類變量分配內存并設置類變量初始值的階段,這些內存都將在方法區中分配


解析(符號引用轉直接引用)

解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程


初始化

初始化階段是執行初始化方法 <clinit> ()方法的過程,是類加載的最后一步,這一步 JVM 才開始真正執行類中定義的 Java 程序代碼(字節碼)


類加載總結

JVM 中內置了三個重要的 ClassLoader

  1. BootstrapClassLoader(啟動類加載器):最頂層的加載類,由 C++實現,通常表示為 null,并且沒有父級,主要用來加載 JDK 內部的核心類庫( %JAVA_HOME%/lib目錄下的 rt.jarresources.jarcharsets.jar等 jar 包和類)以及被 -Xbootclasspath參數指定的路徑下的所有類。
  2. ExtensionClassLoader(擴展類加載器):主要負責加載 %JRE_HOME%/lib/ext 目錄下的 jar 包和類以及被 java.ext.dirs 系統變量所指定的路徑下的所有類。
  3. AppClassLoader(應用程序類加載器):面向我們用戶的加載器,負責加載當前應用 classpath 下的所有 jar 包和類

除了這三種類加載器之外,用戶還可以加入自定義的類加載器來進行拓展,以滿足自己的特殊需求。就比如說,我們可以對 Java 類的字節碼( .class 文件)進行加密,加載時再利用自定義的類加載器對其解密

除了 BootstrapClassLoader 是 JVM 自身的一部分之外,其他所有的類加載器都是在 JVM 外部實現的,并且全都繼承自 ClassLoader抽象類。這樣做的好處是用戶可以自定義類加載器,以便讓應用程序自己決定如何去獲取所需的類

為什么 獲取到 ClassLoadernull就是 BootstrapClassLoader 加載的呢?

這是因為BootstrapClassLoader 由 C++ 實現,由于這個 C++ 實現的類加載器在 Java 中是沒有與之對應的類的,所以拿到的結果是 null


類加載器有哪些?

主要有四種類加載器:

  1. 啟動類加載器(Bootstrap ClassLoader)?來加載 java 核?類庫,?法被 java 程序直接引?。
  2. 擴展類加載器(extensions class loader):它?來加載 Java 的擴展庫。Java 虛擬機的實現會提供?個擴展庫?錄。該類加載器在此?錄??查找并加載 Java 類。
  3. 系統類加載器(system class loader):它根據 Java 應?的類路徑(CLASSPATH)來加載 Java 類。?般來說,Java 應?的類都是由它來完成加載的。可以通ClassLoader.getSystemClassLoader()來獲取它。
  4. 用戶自定義類加載器 (user class loader),?戶通過繼承 java.lang.ClassLoader 類的?式??實現的類加載器


如何自定義類加載器?

我們前面也說說了,除了 BootstrapClassLoader 其他類加載器均由 Java 實現且全部繼承自java.lang.ClassLoader。如果我們要自定義自己的類加載器,很明顯需要繼承 ClassLoader抽象類

ClassLoader 類有兩個關鍵的方法:

  • protected Class loadClass(String name, boolean resolve):加載指定二進制名稱的類,實現了雙親委派機制 name 為類的二進制名稱,resolve 如果為 true,在加載時調用 resolveClass(Class<?> c) 方法解析該類。
  • protected Class findClass(String name):根據類的二進制名稱來查找類,默認實現是空方法。

官方 API 文檔中寫到:

Subclasses of ClassLoader are encouraged to override findClass(String name), rather than this method.

建議 ClassLoader子類重寫 findClass(String name)方法而不是loadClass(String name, boolean resolve) 方法

如果我們不想打破雙親委派模型

需要重寫 ClassLoader 類中的 findClass() 方法即可,無法被父類加載器加載的類最終會通過這個方法被加載

如果我們想打破雙親委派模型

需要重寫 loadClass() 方法


說一下類卸載

卸載類即該類的 Class 對象被 GC。

卸載類需要滿足 3 個要求:

  1. 該類的所有的實例對象都已被 GC,也就是說堆不存在該類的實例對象。
  2. 該類沒有在其他任何地方被引用
  3. 該類的類加載器的實例已被 GC

所以,在 JVM 生命周期內,由 jvm 自帶的類加載器加載的類是不會被卸載的

但是由我們自定義的類加載器加載的類是可能被卸載的

只要想通一點就好了,JDK 自帶的 BootstrapClassLoader, ExtClassLoader, AppClassLoader 負責加載 JDK 提供的類,所以它們(類加載器的實例)肯定不會被回收。而我們自定義的類加載器的實例是可以被回收的,所以使用我們自定義加載器加載的類是可以被卸載掉的


什么是雙親委派機制?

雙親委派模型的工作過程

雙親委派模型的?作過程:如果?個類加載器收到了類加載的請求,它?先不會??去嘗試加載這個類,?是把這個請求委派給父類加載器去完成,每?個層次的類加載器都是如此

因此所有的加載請求最終都應該傳送到最頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求時,子加載器才會嘗試自己去完成加載


雙親委派模型介紹

類加載器有很多種,當我們想要加載一個類的時候,具體是哪個類加載器加載呢?這就需要提到雙親委派模型了

  • ClassLoader 類使用委托模型來搜索類和資源
  • 雙親委派模型要求除了頂層的啟動類加載器外,其余的類加載器都應有自己的父類加載器
  • ClassLoader 實例會在試圖親自查找類或資源之前,將搜索類或資源的任務委托給其父類加載器

下圖展示的各種類加載器之間的層次關系被稱為類加載器的“雙親委派模型(Parents Delegation Model)

從下往上判斷類是否被加載

從上往下嘗試加載類

?


說一下雙親委派模型的執行流程?

簡單總結一下雙親委派模型的執行流程:

1.在類加載的時候,系統會首先判斷當前類是否被加載過。已經被加載的類會直接返回,否則才會嘗試加載(每個父類加載器都會走一遍這個流程)。

2.類加載器在進行類加載的時候,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成(調用父加載器 loadClass()方法來加載類)。這樣的話,所有的請求最終都會傳送到頂層的啟動類加載器 BootstrapClassLoader

3.只有當父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載(調用自己的 findClass() 方法來加載類)。

4.如果子類加載器也無法加載這個類,那么它會拋出一個 ClassNotFoundException 異常

拓展一下:

JVM 判定兩個 Java 類是否相同的具體規則:JVM 不僅要看類的全名是否相同,還要看加載此類的類加載器是否一樣。只有兩者都相同的情況,才認為兩個類是相同的。即使兩個類來源于同一個 Class 文件,被同一個虛擬機加載,只要加載它們的類加載器不同,那這兩個類就必定不相同


為什么要用雙親委派機制

?

答案是為了保證應?程序的穩定有序

例如類 java.lang.Object,它存放在 rt.jar 之中,通過雙親委派機制,保證最終都是委派給處于模型最頂端的啟動類加載器進?加載保證 Object 的?致

反之,都由各個類加載器??去加載的話,如果?戶??也編寫了?個名為 java.lang.Object 的類,并放在程序的 ClassPath 中,那系統中就會出現多個不同的 Object 類

可以避免類被重復加載,同時保證我們的核心API不被修改


說一下雙親委派模型的好處

雙親委派模型保證了 Java 程序的穩定運行,可以避免類的重復加載(JVM 區分不同類的方式不僅僅根據類名,相同的類文件被不同的類加載器加載產生的是兩個不同的類)

保證了 Java 的核心 API 不被篡改

如果沒有使用雙親委派模型,而是每個類加載器加載自己的話就會出現一些問題:

比如我們編寫一個稱為 java.lang.Object 類的話,那么程序運行的時候,系統就會出現兩個不同的 Object 類。雙親委派模型可以保證加載的是 JRE 里的那個 Object 類,而不是你寫的 Object

這是因為 AppClassLoader 在加載你的 Object 類時,會委托給 ExtClassLoader 去加載,而 ExtClassLoader 又會委托給 BootstrapClassLoaderBootstrapClassLoader 發現自己已經加載過了 Object 類,會直接返回,不會去加載你寫的 Object

可以避免類被重復加載,同時保證我們的核心API不被修改


如何破打破雙親委派機制?

?

自定義加載器的話,需要繼承 ClassLoader

如果我們不想打破雙親委派模型,就重寫 ClassLoader 類中的 findClass() 方法即可,無法被父類加載器加載的類最終會通過這個方法被加載。

但是,如果想打破雙親委派模型則需要重寫 loadClass() 方法

?


我們有什么場景需要破壞我們的雙親委派機制

?

自定義類場景

破壞雙親委派機制的場景
1. 動態加載和熱更新:

在某些開發環境中,可能需要動態加載新的類或更新現有類。為了實現熱更新,可能需要創建一個自定義的類加載器,繞過雙親委派機制,以便直接加載新的類定義。

2. 插件架構:

在插件系統中,可能需要允許插件直接使用特定的類,而這些類可能與主應用程序中的類同名。通過自定義類加載器,可以避免加載主應用程序中的同名類,從而實現插件的獨立性。

3. 隔離不同版本的庫:

有時,應用程序可能需要同時使用同一庫的不同版本。通過創建不同的類加載器,可以加載不同版本的庫而不發生沖突,從而破壞雙親委派機制。

4. 安全性需求:

在某些安全敏感的應用場景中,可能需要自定義類加載器以實現更嚴格的安全控制。例如,可以限制某些類的加載,或加載特定來源的類。

5. 測試和調試:

在單元測試或調試過程中,可能需要加載特定版本的類或模擬某些類的行為。自定義類加載器可以幫助實現這種需求


你覺得應該怎么實現一個熱部署功能

?

Java類的加載過程

我們已經知道了 Java 類的加載過程。?個 Java 類?件到虛擬機?的對象,要經過如下過程:

?先通過 Java 編譯器,將 Java ?件編譯成 class 字節碼,

類加載器讀取 class 字節碼,再將類轉化為實例,

對實例 newInstance 就可以?成對象。

類加載器 ClassLoader 的功能

也就是將 class 字節碼轉換到類的實例。在 Java 應?中,所有的實例都是由類加載器加載而來

?般在系統中,類的加載都是由系統?帶的類加載器完成,

?且對于同?個全限定名的 java 類(如 com.csiar.soc.HelloWorld)

只能被加載?次,而且無法被卸載

這個時候問題就來了,如果我們希望將 java 類卸載,并且替換更新版本的 java 類,該怎么做呢?

既然在類加載器中,Java 類只能被加載?次,并且?法卸載。

那么我們是不是可以直接把 Java 類加載器干掉呢?

答案是可以的

自定義類加載器

我們可以?定義類加載器,并重寫 ClassLoader 的 findClass ?法。

想要實現熱部署可以分以下三個步驟:

1)銷毀原來的?定義 ClassLoader

2)更新 class 類?件

3)創建新的 ClassLoader 去加載更新后的 class 類?件。

到此,?個熱部署的功能就這樣實現了


Tomcat 的類加載機制了解嗎

Tomcat 是主流的 Java Web 服務器之?,為了實現?些特殊的功能需求,?定義了?些類加載器。

Tomcat 類加載器如下:

Tomcat 實際上也是破壞了雙親委派模型的

Tomact 是 web 容器,可能需要部署多個應?程序。不同的應?程序可能會依賴同?個第三?類庫的不同版本,但是不同版本的類庫中某?個類的全路徑名可能是?樣的。如多個應?都要依賴 hollis.jar,但是 A 應?需要依賴1.0.0 版本,但是 B 應?需要依賴 1.0.1 版本。這兩個版本中都有?個類是 com.hollis.Test.class。如果采?默認的雙親委派類加載機制,那么?法加載多個相同的類

所以,Tomcat 破壞了雙親委派原則,提供隔離的機制,為每個 web 容器單獨提供?個 WebAppClassLoader 加載器。每?個 WebAppClassLoader 負責加載本身的?錄下的 class ?件,加載不到時再交 CommonClassLoader加載,這和雙親委派剛好相反

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

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

相關文章

AI數字人實現原理

隨著人工智能與數字技術的快速發展&#xff0c;AI數字人&#xff08;Digital Human&#xff09;作為新一代人機交互媒介&#xff0c;正在多個行業中快速落地。無論是在虛擬主播、在線客服、教育培訓&#xff0c;還是在數字代言、元宇宙中&#xff0c;AI數字人都扮演著越來越重要…

Android開發-數據庫SQLite

在Android應用開發中&#xff0c;當需要存儲結構化數據時&#xff0c;SQLite是一個非常強大的工具。SQLite是一款輕量級的關系型數據庫管理系統&#xff0c;它內嵌于Android系統中&#xff0c;支持SQL語法&#xff0c;并且不需要單獨的服務器進程或系統配置。本文將介紹如何在A…

android實現USB通訊

在 Android 上枚舉 USB 設備除了使用 UsbManager.getDeviceList() 方法外&#xff0c;還有以下幾種常見的方式&#xff1a; 1. 使用 USB 設備過濾器&#xff08;XML 配置&#xff09; 通過在 AndroidManifest.xml 中配置 USB 設備過濾器&#xff0c;可以讓系統自動檢測并通知…

FFmpeg視頻編碼的完整操作指南

步驟如下&#xff1a; 安裝和準備FFmpeg&#xff1a;確保包含所需編碼器&#xff08;如libx264&#xff09;。基本命令行編碼&#xff1a;使用ffmpeg命令進行轉碼&#xff0c;設置視頻編碼器、CRF、預設等。API編碼流程&#xff08;針對開發者&#xff09;&#xff1a; a. 注冊…

鴻蒙 UIAbility組件與UI的數據同步和窗口關閉

使用 EventHub 進行數據通信 Stage模型概念圖 根據 Stage 模型概念圖 UIAbility 先于 ArkUI Page 創建 所以&#xff0c;事件要先 .on 訂閱 再 emit 發布 假如現在有頁面 Page1 和他的 UIAbility // src/main/ets/page1ability/Page1Ability.ets onCreate(want: Want, laun…

全棧工程師實戰手冊:LuatOS日志系統開發指南!

本文聚焦LuatOS-log庫的實戰應用場景&#xff0c;通過完整案例演示日志模塊集成、格式定制及遠程同步方案&#xff0c;幫助全棧開發者構建靈活可靠的日志管理框架。下面&#xff0c;我們一起來認識LuatOS的log庫&#xff01; 一、 log.info() log info()主要打印一些正常的…

STM32-USART串口通信(9)

一、通信接口介紹 通信的目的&#xff1a;將一個設備的數據傳送到另一個設備&#xff0c;擴展硬件系統。 當STM32想要實現一些功能&#xff0c;但是需要外掛一些其他模塊才能實現&#xff0c;這就需要在兩個設備之間連接上一根或多跟通信線&#xff0c;通過通信線路發送或者接…

【MoveIt 2】使用 MoveIt 任務構造器(MoveIt Task Constructor)進行拾取和放置

本教程將引導您創建一個使用 MoveIt 任務構造器規劃抓取和放置操作的包。MoveIt 任務構造器&#xff08;https://github.com/moveit/moveit_task_constructor/tree/ros2/&#xff09;提供了一種為包含多個不同子任務&#xff08;稱為階段&#xff09;的任務進行規劃的方法。如果…

破解商業綜合體清潔管理困局:商業空間AI智能保潔管理系統全場景解決方案

方案整體概述 隨著商業綜合體日益向智能化、精細化管理轉型&#xff0c;傳統保潔工作面臨人員監管難、清潔效果評估難、應急響應滯后等諸多挑戰。為解決這些痛點&#xff0c;本系統依托計算機視覺、行為識別、圖像分割與深度學習等AI技術&#xff0c;構建一套集人員管理、工作…

spring響應式編程系列:異步消費數據

目錄 示例 大致流程 parallel cache PARALLEL_SUPPLIER newParallel init publishOn new MonoSubscribeOnValue ???????subscribe ???????new LambdaMonoSubscriber ???????MonoSubscribeOnValue.subscribe ???????onSubscribe ??…

視頻編解碼學習十二之Android疑點

一、android.view.SurfaceControl.setDisplaySurface的作用 android.view.SurfaceControl.setDisplaySurface 是 Android 系統中一個 native 層級別的 API&#xff0c;主要用于 設置某個物理顯示屏&#xff08;Display&#xff09;的輸出 Surface&#xff0c;屬于 SurfaceFlin…

家用或辦公 Windows 電腦玩人工智能開源項目配備核顯的必要性(含 NPU 及顯卡類型補充)

一、GPU 與顯卡的概念澄清 首先需要明確一個容易誤解的概念&#xff1a;GPU 不等同于顯卡。 顯卡和GPU是兩個不同的概念。 【概念區分】 在討論圖形計算領域時&#xff0c;需首先澄清一個常見誤區&#xff1a;GPU&#xff08;圖形處理單元&#xff09;與顯卡&#xff08;視…

Python----神經網絡(《Deep Residual Learning for Image Recognition》論文和ResNet網絡結構)

一、論文 1.1、論文基本信息 標題&#xff1a;Deep Residual Learning for Image Recognition 作者&#xff1a;Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun 單位&#xff1a;Microsoft Research 會議&#xff1a;CVPR 2016 主要貢獻&#xff1a;提出了一種深度殘…

Qt/C++開發監控GB28181系統/錄像文件查詢/錄像回放/倍速播放/錄像文件下載

一、前言 搞定了實時預覽后&#xff0c;另一個功能就是錄像回放&#xff0c;錄像回放和視頻點播功能完全一致&#xff0c;唯一的區別就是發送點播的sdp信息中攜帶了開始時間和結束時間&#xff0c;因為是錄像文件&#xff0c;所以有這個時間&#xff0c;而實時視頻預覽這個對應…

在Spark搭建YARN

&#xff08;一&#xff09;什么是SparkONYarn模式 Spark on YARN&#xff08;Yet Another Resource Negotiator&#xff09;是 Spark 框架在 Hadoop 集群中運行的一種部署模式&#xff0c;它借助 Hadoop YARN 來管理資源和調度任務。 架構組成 ResourceManager&#xff1a;作…

SpringAI

機器學習&#xff1a; 定義&#xff1a;人工智能的子領域&#xff0c;通過數據驅動的方法讓計算機學習規律&#xff0c;進行預測或決策。 核心方法&#xff1a; 監督學習&#xff08;如線性回歸、SVM&#xff09;。 無監督學習&#xff08;如聚類、降維&#xff09;。 強化學…

如何用Redis實現分布式鎖?RedLock算法的核心思想?Redisson的看門狗機制原理?

一、Redis分布式鎖基礎實現 public class RedisDistributedLock {private JedisPool jedisPool;private String lockKey;private String clientId;private int expireTime 30; // 默認30秒public boolean tryLock() {try (Jedis jedis jedisPool.getResource()) {// NX表示不…

前端面試寶典---js垃圾回收機制

什么是垃圾回收 垃圾回收是指一種自動內存管理機制&#xff0c;當聲明一個變量時&#xff0c;會在內存中開辟一塊內存空間用于存放這個變量。當這個變量被使用過后&#xff0c;可能再也不需要它了&#xff0c;此時垃圾回收器會自動檢測并回收這些不再使用的內存空間。垃圾回收…

阿里媽媽LMA2新進展:集成大語言模型與電商知識的通用召回大模型URM

近日&#xff0c;阿里媽媽在國際頂級學術會議 —— 國際萬維網大會&#xff08;International World Wide Web Conference, 簡稱WWW&#xff09;上共同主持了計算廣告算法技術相關的Tutorial&#xff08;講座&#xff09;&#xff0c;介紹了計算廣告領域的技術發展脈絡&#xf…

數字孿生實時監控汽車零部件工廠智能化巡檢新范式

在汽車制造業面臨數字化轉型時&#xff0c;汽車零部件工廠也面臨著提升生產效率、降低運營成本和增強市場競爭力的多重挑戰。傳統的巡檢方式已經難以滿足現代工廠對高效、精準管理和實時決策的需求。數字孿生系統的出現&#xff0c;為汽車零部件工廠提供了一種創新的智能化巡檢…