深入理解 Linux 內核進程管理

在 Linux 系統中,進程是資源分配和調度的基本單位,內核對進程的高效管理直接決定了系統的性能與穩定性。本文將從進程描述符的結構入手,逐步剖析進程的創建、線程實現與進程終結的完整生命周期,帶您深入理解 Linux 內核的進程管理機制。

一、進程描述符

要管理進程,內核首先需要一種結構化的方式記錄進程的所有信息 —— 這就是進程描述符(task_struct)?的核心作用。所有進程的描述符通過 “任務隊列(task list)” 這個雙向循環鏈表組織,鏈表中的每一項都是task_struct類型(定義于<linux/sched.h>),包含了進程運行所需的全部關鍵信息:

  • 進程的地址空間(虛擬內存布局)
  • 已打開的文件描述符表
  • 掛起的信號與信號處理方式
  • 進程狀態、PID、PPID 等身份信息
  • 資源限制、記賬信息等

1.1 進程描述符的分配

Linux 內核對task_struct的分配方式,在 2.6 版本前后有顯著變化,核心目標是適配不同硬件架構的效率需求:

  • 2.6 版本前task_struct直接存放在進程內核棧的尾部。對于 x86 這類寄存器較少的架構,只需通過棧指針即可計算出task_struct的位置,無需額外寄存器存儲地址,極大節省了硬件資源。
  • 2.6 版本及以后:引入slab 分配器管理task_struct的分配。此時內核會先在棧底 / 棧頂創建struct thread_info結構(定義于<asm/thread_info.h>),thread_info中包含一個指向task_struct的指針。這種方式既保證了內存分配的高效性(slab 避免碎片),又兼容了舊架構的棧指針尋址邏輯。

thread_infotask_struct的關系可理解為:thread_info是 “輕量級進程上下文”,而task_struct是 “完整進程信息庫”,二者通過指針關聯。

1.2 如何找到當前進程的描述符?current 宏的實現

內核需要快速獲取 “當前正在執行的進程” 的task_struct,這依賴于current宏,其底層邏輯與硬件架構強相關:

  • x86 架構:內核棧的大小固定(如 8KB),thread_info存放在棧的固定位置。通過將棧指針的后 13 個有效位屏蔽(13 位對應 8KB=213),即可得到thread_info的起始地址,再通過thread_info->task指針找到task_struct。這一過程通過current_thread_info()函數封裝,最終current等價于current_thread_info()->task
  • 其他架構:可能通過寄存器直接存儲task_struct地址(如 ARM),但核心目標都是 “快速定位當前進程描述符”。

此外,進程的 PID 上限并非固定,可通過修改/proc/sys/kernel/pid_max調整(默認值通常為 32768,64 位系統可支持更高)。

1.3 進程狀態:task_struct 中的 “運行狀態機”

task_structstate字段記錄了進程的當前狀態,內核通過狀態控制進程的調度與資源分配。Linux 定義了 5 種核心狀態,每種狀態對應明確的運行場景:

狀態常量狀態含義
TASK_RUNNING可執行狀態:要么正在 CPU 上運行,要么在運行隊列中等待 CPU 調度
TASK_INTERRUPTIBLE可中斷阻塞:等待某條件達成(如等待 IO 完成、等待信號),收到信號后會被喚醒
TASK_UNINTERRUPTIBLE不可中斷阻塞:同樣等待條件,但收到信號也不會喚醒(如磁盤 IO 關鍵階段,避免數據損壞)
__TASK_TRACED被跟蹤狀態:進程被其他進程調試(如ptrace工具),執行受調試器控制
__TASK_STOPPED停止狀態:進程暫停執行(如收到SIGSTOP信號,或調試時的斷點暫停)

注意:__TASK_TRACED__TASK_STOPPED中的下劃線表示 “內核內部狀態”,用戶空間通過ps等工具看到的是經過封裝的狀態(如T代表停止,t代表跟蹤)。

1.4 如何修改進程狀態?set_task_state 的必要性

直接通過task->state = state修改狀態看似簡單,但存在并發風險(如修改時進程正被調度)。內核提供set_task_state(task, state)函數(定義于<linux/sched.h>),其核心作用是:

  • 保證狀態修改的原子性,避免并發沖突
  • 隱含內存屏障,確保狀態修改對其他 CPU 可見

若要修改 “當前進程” 的狀態,可直接使用set_current_state(state),它等價于set_task_state(current, state),是內核代碼中的常用封裝。

1.5 進程上下文:用戶空間與內核空間的切換

進程的執行分為 “用戶空間” 和 “內核空間” 兩個場景,二者的切換對應 “進程上下文” 的切換:

  • 用戶空間執行:進程運行自己的代碼(如 C 語言編寫的應用程序),操作的是用戶態內存,無法直接訪問內核資源。
  • 內核空間執行:當進程觸發系統調用(如open()fork())或異常(如缺頁錯誤、除零錯誤)時,CPU 會切換到內核態,此時內核 “代表進程執行”,即處于進程上下文

進程上下文的核心特點是:內核執行的操作與當前進程強相關(如為進程分配內存、處理進程的 IO 請求),且必須通過系統調用 / 異常這兩個 “合法接口” 進入,確保內核安全。

1.6 進程家族樹:parent 與 children 的關聯

Linux 中的進程存在明確的 “父子關系”,這種關系通過task_struct中的兩個字段維護:

  • parent:指向父進程的task_struct指針(如current->parent可獲取當前進程的父進程)。
  • children:一個鏈表頭,記錄當前進程的所有子進程(子進程通過sibling字段接入鏈表)。

通過這兩個字段,內核可輕松遍歷進程家族樹,例如:

  1. 遍歷當前進程的所有子進程
    struct task_struct *task;
    struct list_head *list;
    // 遍歷children鏈表
    list_for_each(list, &current->children) {// 通過list_entry從鏈表項獲取task_structtask = list_entry(list, struct task_struct, sibling);
    }
    
  2. 追溯當前進程的所有祖先(直到 init 進程)
    struct task_struct *task;
    for (task = current; task != &init_task; task = task->parent) {// init_task是所有進程的“根”,PID為1
    }
    

二、進程創建

Linux 創建新進程的核心是fork() + exec()?的組合:

  • fork():復制當前進程(父進程)的所有資源,創建一個幾乎完全相同的子進程(區別僅在于 PID、PPID、掛起信號等少量信息)。
  • exec():替換子進程的地址空間,將新的可執行文件加載到內存并開始運行(至此子進程與父進程徹底區分)。

這種 “先復制、后替換” 的邏輯,配合 “寫時拷貝” 技術,實現了高效的進程創建。

2.1 寫時拷貝(Copy-On-Write):避免 “無用的復制”

傳統的fork()會直接復制父進程的所有內存頁(包括代碼段、數據段、堆、棧),但如果子進程緊接著調用exec(),這些復制的內存頁會被立即替換 —— 大量復制操作完全無用,浪費 CPU 和內存資源。

寫時拷貝(COW)?技術徹底解決了這個問題:

  • fork()創建子進程時,內核不復制任何內存頁,而是讓父進程和子進程共享所有內存頁,并將這些頁標記為 “只讀”。
  • 當父進程或子進程嘗試寫入某內存頁時,CPU 會觸發 “頁錯誤”,內核此時才會為該頁創建副本,分配新的物理內存并修改頁表。
  • 最終fork()的開銷僅為:復制父進程的頁表 + 創建子進程的task_struct,效率大幅提升。

2.2 fork () 的底層實現:從 clone () 到 copy_process ()

用戶空間調用fork()后,內核的執行流程可拆解為三個關鍵函數:clone()?→?do_fork()?→?copy_process(),其中do_fork()是核心調度者(定義于kernel/fork.c),copy_process()負責完成子進程的創建細節:

copy_process () 的核心步驟(共 8 步):
  1. 創建基礎結構:調用dup_task_struct()為子進程創建內核棧thread_infotask_struct,并將父進程的對應結構數據復制到子進程(此時子進程與父進程幾乎完全一致)。
  2. 資源限制檢查:確保創建子進程后,當前用戶的進程總數不超過ulimit等資源限制(避免惡意創建進程耗盡系統資源)。
  3. 子進程與父進程 “劃清界限”:將task_struct中與父進程無關的字段清 0 或初始化(如掛起的信號、CPU 時間統計、進程優先級等),僅保留必要的共享信息(如打開的文件、地址空間)。
  4. 設置子進程狀態為不可中斷:將子進程的state設為TASK_UNINTERRUPTIBLE,防止子進程在初始化完成前被調度執行(避免數據不一致)。
  5. 更新進程標志:調用copy_flags()修改task_structflags字段:
    • 清除PF_SUPERPRIV標志(子進程不繼承父進程的超級用戶權限,需重新通過setuid等方式獲取)。
    • 設置PF_FORKNOEXEC標志(標記子進程尚未調用exec(),后續exec()會清除該標志)。
  6. 分配 PID:調用alloc_pid()為子進程分配唯一的 PID,確保 PID 在系統中不重復。
  7. 拷貝 / 共享資源:根據clone()傳遞的參數標志(如CLONE_VMCLONE_FILES),決定子進程與父進程是共享還是拷貝資源:
    • 若為fork(),則拷貝地址空間、文件描述符表等(但基于 COW 延遲拷貝)。
    • 若為線程創建(后續會講),則共享這些資源。
  8. 返回子進程描述符:完成初始化后,返回指向子進程task_struct的指針。
do_fork () 的最終調度:讓子進程先執行

copy_process()成功返回后,do_fork()會喚醒子進程(將state改為TASK_RUNNING),并優先調度子進程執行。這一設計的原因是:

  • 子進程通常會立即調用exec(),若父進程先執行,可能會寫入內存頁觸發 COW 拷貝;而子進程先執行exec(),可直接替換地址空間,完全避免 COW 的額外開銷。

2.3 vfork ()

vfork()fork()功能相似,但有一個關鍵區別:vfork () 不拷貝父進程的頁表項,子進程直接共享父進程的地址空間。這種設計進一步降低了創建開銷,但也帶來了嚴格限制:

  • 子進程在調用exec()exit()前,不能修改任何內存數據(否則會直接破壞父進程的地址空間)。
  • 子進程執行期間,父進程會被阻塞,直到子進程調用exec()exit()

vfork()的底層通過clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)實現,其中CLONE_VM表示 “共享地址空間”,CLONE_VFORK表示 “父進程阻塞直到子進程退出 /exec”。

三、Linux 的線程實現

與 Windows、Solaris 等系統不同,Linux 內核中沒有 “線程” 的概念—— 所有線程都被視為 “共享部分資源的進程”。內核不提供專門的線程數據結構或調度算法,而是通過clone()的參數控制進程間的資源共享程度,從而實現 “線程” 的語義。

3.1 線程創建:通過 clone () 的標志控制資源共享

用戶空間的線程庫(如 POSIX 線程庫 pthread),底層通過調用clone()并傳遞特定標志,讓新進程與父進程共享關鍵資源,從而表現為 “線程”。核心標志及其含義如下:

clone () 標志資源共享含義
CLONE_VM共享地址空間(代碼段、數據段、堆、棧)—— 線程的核心特征
CLONE_FS共享文件系統信息(如當前工作目錄、根目錄、文件權限掩碼)
CLONE_FILES共享打開的文件描述符表
CLONE_SIGHAND共享信號處理函數表

因此,創建一個 POSIX 線程的clone()調用如下:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);

對比不同進程創建方式的clone()參數:

  • 普通fork()clone(SIGCHLD, 0)(不共享任何核心資源,僅傳遞SIGCHLD信號通知父進程子進程退出)。
  • vfork()clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0)(共享地址空間,父進程阻塞)。

本質上,Linux 的 “線程” 與 “進程” 的區別僅在于 “資源共享程度”:

  • 進程:獨立地址空間、獨立文件表、獨立信號處理。
  • 線程:共享地址空間、共享文件表、共享信號處理,僅保留獨立的task_struct(PID、寄存器上下文、棧等)。

3.2 內核線程:只在內核空間運行的 “特殊進程”

除了用戶空間的線程,Linux 還有內核線程(Kernel Thread)?—— 由內核直接創建和管理,僅在內核空間運行,不涉及用戶空間切換。內核線程的核心特點:

  • 無獨立地址空間task_struct中的mm指針(指向地址空間)被設為NULL,直接使用內核的地址空間。
  • 僅運行內核代碼:用于處理內核級任務(如磁盤 IO 調度、內存回收、定時器處理等),不會切換到用戶態。
  • 可被調度與搶占:與普通進程一樣參與 CPU 調度,支持優先級調整,可被高優先級進程搶占。
  • 只能由內核線程創建:用戶空間無法直接創建內核線程,必須通過內核提供的接口(如kthread_create())。
內核線程的創建與退出(基于<linux/kthread.h>
  • 創建并初始化(未運行)kthread_create(threadfn, data, namefmt, ...)
    • threadfn:內核線程的入口函數(返回int,參數為data)。
    • namefmt:線程名稱(如"kworker/%d:%d"),用于ps等工具查看。
    • 返回值:指向線程task_struct的指針,此時線程狀態為TASK_UNINTERRUPTIBLE(未運行)。
  • 喚醒內核線程:調用wake_up_process(task)將線程狀態改為TASK_RUNNING,使其進入調度隊列。
  • 創建并直接運行kthread_run(threadfn, data, namefmt, ...)(封裝了kthread_create()?+?wake_up_process(),一步完成創建與喚醒)。
  • 退出內核線程kthread_stop(task)(向線程發送退出信號,等待線程執行完threadfn后回收資源)。

常見的內核線程如kworker(工作隊列線程)、kswapd0(內存回收線程)、ksoftirqd(軟中斷處理線程)等,通過ps -ef可觀察到它們的名稱以k開頭。

四、進程終結

進程的終結并非 “一鍵刪除”,而是一個分階段的資源回收過程,核心目標是確保 “資源不泄漏”—— 即使進程退出,也要先歸還內核分配的內存、文件句柄等資源,再清理進程描述符。

4.1 do_exit ():進程終結的 “核心清理函數”

當進程通過exit()系統調用主動退出、執行到main()函數返回,或因觸發致命信號(如SIGKILLSIGSEGV)被動終止時,內核都會調用do_exit()函數(定義于kernel/exit.c),完成進程的 “自我清理”。該函數通過 9 個關鍵步驟,逐步釋放進程占用的資源:

  1. 標記進程為 “退出中”
    首先將task_struct(進程描述符)中的flags成員設置為PF_EXITING。這個標志是內核組件的 “信號”—— 告知調度器、內存分配模塊等:“該進程正在退出,無需再為其分配新資源或調度執行”。例如,調度器檢測到PF_EXITING后,會跳過對該進程的 CPU 調度邏輯;內存模塊也不會再為其分配物理頁,從源頭避免資源浪費。

  2. 清理內核定時器
    調用del_timer_sync()函數,刪除進程關聯的所有內核定時器。該函數的核心是 “同步清理”:不僅會將排隊中的定時器從內核定時器鏈表中移除,還會等待當前正在執行的定時器處理程序完成(若存在)。這一步是為了防止定時器回調函數訪問已處于退出狀態的進程資源(如進程地址空間、文件描述符),避免內核崩潰或數據損壞(data corruption)。

  3. 輸出 BSD 記賬信息
    若系統開啟了 BSD 風格的進程記賬功能(可通過acct系統調用啟用),do_exit()會調用acct_update_integrals()函數,將進程的運行統計數據(如總 CPU 占用時間、用戶態 / 內核態運行時長、內存峰值占用量、IO 操作次數等)寫入記賬日志文件(通常路徑為/var/log/account/pacct)。這些數據是系統資源審計、進程行為分析的關鍵依據,例如管理員通過sa命令查看進程資源使用排行時,依賴的就是該步驟記錄的信息。

  4. 釋放進程地址空間
    調用exit_mm()函數,處理進程的內存描述符mm_struct(該結構是進程虛擬地址空間的核心,包含頁表、虛擬內存區域 VMA、內存權限等信息)。exit_mm()的執行邏輯分兩種情況:

    • mm_struct的引用計數為 0(意味著沒有其他進程 / 線程共享該地址空間,如普通單進程場景):則徹底釋放頁表、VMA 結構,并通過內核頁回收機制將關聯的物理內存頁歸還給系統。
    • 若引用計數大于 0(如多線程共享地址空間):僅解除當前進程與mm_struct的關聯,不釋放實際內存資源,確保其他線程能正常訪問共享地址空間。
  5. 退出 IPC 信號量隊列
    調用sem_exit()函數,檢查進程是否處于 IPC 信號量的等待隊列中(例如通過sem_wait()系統調用阻塞等待信號量)。若存在,sem_exit()會將進程從等待隊列中移除,并更新信號量的等待計數,避免其他進程調用sem_post()時喚醒已退出的進程,確保 IPC 信號量機制的正確性和穩定性。

  6. 釋放文件與文件系統資源
    分兩步清理進程的文件相關資源,避免文件句柄泄漏:

    • 調用exit_files():進程的files_struct結構存儲了打開的文件描述符表,exit_files()會遞減files_struct的引用計數。若計數為 0,會遍歷文件描述符表,調用fput()關閉所有已打開的文件,釋放對應的file結構體。
    • 調用exit_fs():進程的fs_struct結構記錄了當前工作目錄、根目錄、文件權限掩碼(umask)等信息,exit_fs()會遞減fs_struct的引用計數,若計數為 0 則釋放該結構,將資源歸還給內核。
  7. 設置進程退出代碼
    exit()系統調用傳入的退出代碼(或內核生成的退出代碼,如信號終止時的信號編號)存入task_structexit_code成員中。這一代碼是進程退出狀態的核心標識,后續父進程通過wait()waitpid()等函數獲取子進程狀態時,本質就是讀取該字段的值 —— 例如echo $?命令顯示的 “上一個進程退出碼”,正是從子進程的exit_code中讀取的。

  8. 通知父進程并處理子進程領養
    調用exit_notify()函數,完成三項關鍵工作:

    • 向父進程發送SIGCHLD信號:父進程若注冊了SIGCHLD的處理函數(或使用默認處理邏輯),會感知到子進程的退出事件,進而觸發后續的wait()操作。
    • 領養子進程:若當前進程有未退出的子進程,exit_notify()會為這些子進程重新指定 “養父”—— 優先選擇當前進程所在線程組中的其他存活線程;若線程組中無其他線程,則將子進程的父進程設為init進程(PID=1),確保所有進程都有父進程管理,避免 “孤兒進程” 長期存在。
    • 設置僵尸狀態:將task_structexit_state成員設為EXIT_ZOMBIE(僵尸狀態)。此時進程已停止運行,但task_struct仍被保留,用于存儲退出信息供父進程讀取。
  9. 主動調度切換進程
    最后調用schedule()函數,主動放棄 CPU 資源,觸發內核調度。由于當前進程已處于EXIT_ZOMBIE狀態,調度器會將其從運行隊列中移除,且永遠不會再被調度執行。schedule()會選擇其他處于TASK_RUNNING狀態的進程投入運行,確保 CPU 資源不閑置,維持系統正常的調度流程。

4.2 釋放進程描述符:從僵尸狀態到徹底清理

調用do_exit()后,進程進入EXIT_ZOMBIE狀態(僵尸進程)—— 此時進程已停止運行、大部分資源已釋放,但task_struct(進程描述符)仍被保留。內核保留task_struct的原因是 “為父進程保留退出信息”,只有當父進程通過wait()系列函數獲取這些信息后,內核才會調用release_task()函數,徹底釋放進程描述符。

4.2.1 wait () 系列函數的底層邏輯

用戶空間的wait()waitpid()等函數,底層均通過wait4()系統調用實現。父進程調用wait4()后,內核會檢查子進程的狀態:

  • 若子進程已處于EXIT_ZOMBIE狀態:則讀取子進程的exit_code等信息,返回給父進程,并觸發release_task()釋放子進程的task_struct
  • 若子進程仍在運行:則將父進程阻塞,直到子進程退出并進入EXIT_ZOMBIE狀態,再執行上述邏輯。

4.2.2 release_task ():徹底清理進程描述符

release_task()是釋放task_struct的核心函數,主要完成 4 項工作:

  1. 從內核數據結構中移除進程
    release_task()首先調用__exit_signal()函數,該函數進一步調用_unhash_process(),而_unhash_process()會調用detach_pid()

    • pidhash哈希表中刪除進程:pidhash是內核通過 PID 快速查找進程的哈希表,移除后該 PID 可被新進程復用。
    • 從任務隊列(task list)中刪除進程:task list是存儲所有進程task_struct的雙向循環鏈表,移除后進程不再被內核遍歷和管理。
  2. 釋放僵死進程的剩余資源
    __exit_signal()會繼續釋放僵死進程殘留的資源:包括進程的私有信號隊列、信號處理相關結構,并更新系統的進程統計數據(如總進程數遞減),確保所有與進程相關的內核資源都被完整回收。

  3. 處理線程組的收尾工作
    若當前進程是線程組中的最后一個進程,且線程組的領頭進程(thread group leader)已死亡,release_task()會通知領頭進程的父進程 —— 告知其 “線程組已完全退出”,確保線程組的資源被徹底清理,避免殘留的線程組信息占用內核資源。

  4. 釋放進程描述符與內核棧
    最后調用put_task_struct()函數:

    • 釋放進程的內核棧和thread_info結構所占的物理頁:thread_info是進程的輕量級上下文結構,與內核棧緊密關聯,二者會一同被釋放。
    • 釋放task_struct:將task_struct歸還給 slab 分配器(內核用于高效管理小對象內存的機制),供新進程創建時復用,避免內存碎片。

至此,進程的task_struct被徹底釋放,進程在系統中的所有痕跡消失,進程終結流程完全結束。

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

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

相關文章

ACP(三):讓大模型能夠回答私域知識問題

讓大模型能夠回答私域知識問題 未經過特定訓練答疑機器人&#xff0c;是無法準確回答“我們公司項目管理用什么工具”這類內部問題。根本原因在于&#xff0c;大模型的知識來源于其訓練數據&#xff0c;這些數據通常是公開的互聯網信息&#xff0c;不包含任何特定公司的內部文檔…

使用Xterminal連接Linux服務器

使用Xterminal連接Linux服務器&#xff08;VMware虛擬機&#xff09;的步驟如下&#xff0c;前提是虛擬機已獲取IP&#xff08;如 192.168.31.105&#xff09;且網絡互通&#xff1a; 一、準備工作&#xff08;服務器端確認&#xff09;確保SSH服務已安裝并啟動 Linux服務器需要…

ChatBot、Copilot、Agent啥區別

以下內容為AI生成ChatBot&#xff08;聊天機器人&#xff09;、Copilot&#xff08;副駕駛&#xff09;和Agent&#xff08;智能體/代理&#xff09;是AI應用中常見的三種形態&#xff0c;它們在人機交互、自動化程度和任務處理能力上有著顯著的區別。特征維度ChatBot (聊天機器…

2025 年大語言模型架構演進:DeepSeek V3、OLMo 2、Gemma 3 與 Mistral 3.1 核心技術剖析

編者按&#xff1a; 在 Transformer 架構誕生八年之際&#xff0c;我們是否真的見證了根本性的突破&#xff0c;還是只是在原有設計上不斷打磨&#xff1f;今天我們為大家帶來的這篇文章&#xff0c;作者的核心觀點是&#xff1a;盡管大語言模型在技術細節上持續優化&#xff0…

基于Matlab GUI的心電信號QRS波群檢測與心率分析系統

心電信號&#xff08;Electrocardiogram, ECG&#xff09;是臨床診斷心臟疾病的重要依據&#xff0c;其中 QRS 波群的準確檢測對于心率分析、心律失常診斷及自動化心電分析系統具有核心意義。本文設計并實現了一套基于 MATLAB GUI 的心電信號處理與分析系統&#xff0c;集成了數…

1臺SolidWorks服務器能帶8-10人并發使用

在工業設計和機械工程領域&#xff0c;SolidWorks作為主流的三維CAD軟件&#xff0c;其服務器部署方案直接影響企業協同效率。通過云飛云共享云桌面技術實現多人并發使用SolidWorks時&#xff0c;實際承載量取決于硬件配置、網絡環境、軟件優化等多維度因素的綜合作用。根據專業…

String、StringBuilder和StringBuffer的區別

目錄一. String&#xff1a;不可變的字符串二.StringBuilder&#xff1a;可變字符串三.StringBuffer&#xff1a;線程安全的可變字符串四.總結在 Java 開發中&#xff0c;字符串處理是日常編碼中最頻繁的操作之一。String、StringBuilder 和 StringBuffer 這三個類雖然都用于操…

Power Automate List Rows使用Fetchxml查詢的一個bug

看一段FetchXML, 這段查詢在XRMtoolbox中的fech test工具里執行完全ok<fetch version"1.0" mapping"logical" distinct"true" no-lock"false"> <entity name"new_projectchange"> <link-entity name"sy…

Letta(MemGPT)有狀態AI代理的開源框架

1. 項目概述Letta&#xff08;前身為 MemGPT&#xff09;是一個用于構建有狀態AI代理的開源框架&#xff0c;專注于提供長期記憶和高級推理能力。該項目是MemGPT研究論文的實現&#xff0c;引入了"LLM操作系統"的概念用于內存管理。核心特點有狀態代理&#xff1a;具…

除了ollama還有哪些模型部署方式?多樣化模型部署方式

在人工智能的浪潮中&#xff0c;模型部署是釋放其強大能力的關鍵一環。大家都知道ollama&#xff0c;它在模型部署領域有一定知名度&#xff0c;操作相對簡單&#xff0c;受到不少人的青睞。但其實&#xff0c;模型部署的世界豐富多樣&#xff0c;今天要給大家介紹一款工具&…

Linux系統學習之進階命令匯總

文章目錄一、系統信息1.1 查看系統信息&#xff1a;uname1.2 查看主機名&#xff1a;hostname1.3 查看cpu信息&#xff1a;1.4 當前已加載的內核模塊: lsmod1.5 查看磁盤空間使用情況: df1.6 管理磁盤分區: fdisk1.7 查看目錄或文件磁盤使用情況: du1.8 查看I/O使用情況: iosta…

算法面試(2)------休眠函數sleep_for和sleep_until

操作系統&#xff1a;ubuntu22.04 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 這兩個函數都定義在 頭文件中&#xff0c;屬于 std::this_thread 命名空間&#xff0c;用于讓當前線程暫停執行一段時間。函數功能sleep_for(rel_time)讓當前線程休眠一段相對時間&…

貪心算法應用:5G網絡切片問題詳解

Java中的貪心算法應用&#xff1a;5G網絡切片問題詳解 1. 5G網絡切片問題概述 5G網絡切片是將物理網絡劃分為多個虛擬網絡的技術&#xff0c;每個切片可以滿足不同業務需求&#xff08;如低延遲、高帶寬等&#xff09;。網絡切片資源分配問題可以抽象為一個典型的優化問題&…

Android WorkManager的概念和使用

1. WorkManager基礎與核心概念 1.1 WorkManager概述 WorkManager是Android Jetpack架構組件庫的核心成員&#xff0c;專為管理可靠的后臺任務而設計。它提供了一套統一的API&#xff0c;用于調度需保障執行的延遲型異步任務&#xff08;如數據同步、日志上傳&#xff09;&…

容器使用卷

1.創建一個卷并讓容器掛載該卷1.創建一個卷[roothost1 ~]# docker volume create test-vol test-vol2.列出本地 Docker 主機上的卷[roothost1 ~]# docker volume ls DRIVER VOLUME NAME local test-vol3.查看該卷的詳細信息[roothost1 ~]# docker volume inspect test-v…

高數基礎知識(下)②

文章目錄七、微分方程7.3 高階線性微分方程7.3.1 線性微分方程的解的結構7.3.2 常系數齊次線性微分方程7.3.3 常系數非齊次線性微分方程八、多元函數微分學8.1 偏導數8.2 全微分8.3 基本定理8.4 復合函數微分法8.5 隱函數微分法8.6 多元函數的極值8.6.1 無條件極值8.6.2 條件極…

從0°到180°,STM32玩轉MG996R舵機

1.MG996R舵機的性能參數參數數值產品型號MG995/MG996R產品重量55 g工作扭矩13 kgcm反應速度53-62 R/M使用溫度-30C ~ 55C死區設置4 微秒插頭類型JR、FUTABA 通用轉動角度180&#xff08;左90&#xff0c;右90&#xff09;舵機類型數碼舵機使用電壓3.0 - 7.2 V工作電流100 mA結構…

[frontend]mermaid code2image

hello everyone, welcome to my bolg, here i will introduce something interesting, and if you are interested it, please just let me know. follow me and send me a message are both avaiable. what is mermaid? Mermaid 是一個工具&#xff0c;它能讓你用簡單的文字代…

Jakarta EE 在 IntelliJ IDEA 中開發簡單留言板應用的實驗指導(附完整代碼)

Jakarta EE 在 IntelliJ IDEA 中開發簡單留言板應用的實驗指導(附完整代碼) 摘要:實驗基于Jakarta EE 9+(兼容Tomcat 10+)、Maven作為構建工具,并在IntelliJ IDEA 2023.2(Community版免費)中進行。項目使用Maven Archetype WebApp模板生成基礎結構,然后升級到J…

JavaScript經典面試題一(JavaScript基礎)

目錄 一、JavaScript中的變量提升 1. 機制 2. 示例 3. 注意事項 4. 總結 二、var、let和const的區別。 1. 作用域&#xff08;Scope&#xff09; 2. 變量提升&#xff08;Hoisting&#xff09; 3. 重新賦值和重新聲明 4. 示例 示例1&#xff1a;作用域和塊級行為 示…