ptmalloc:從內存虛擬化說起

前言

本文并不局限于ptmalloc的原理,而是從linux的內存虛擬化和系統調用原理出發,結合各種語言實現,講明內存分配方面的trade off,力圖事無巨細,追根究底。本文內容包括但不限于:NIO原理、0拷貝原理、內存虛擬化、GC和內存分配、PCB結構、mmap原理和場景、JVM內存分配細節、缺頁異常中斷、PTE、物理頁分配、駐留內存、malloc分配原理、ptmalloc的設計和缺陷、mimalloc設計。

什么是glibc和ptmalloc

glibc提供了一組在所有Linux發行版上都可用的標準化函數。包括ISO C standard library、POSIX實現、內存管理等。其中的內存分配函數ptmalloc2被包括C++、JVM(Native Heap)、Python在內廣泛使用。
ptmalloc2遵循malloc函數的慣例:小內存使用brk分配,大內存使用mmap分配。
同時,ptmalloc2也因為它的內存碎片、內存泄漏和線程間鎖爭用問題而廣受詬病,因此谷歌推出了tcmalloc,facebook推出jemalloc,微軟推出mimalloc來取代它。一般在生產環境也建議根據不同的情況選用不同的內存分配庫替換掉glibc的實現。

思考題1:ptmalloc2的問題會對哪些語言造成影響?為什么?

答案:
對C++、JVM(Native Heap)、Python都有影響。但是對JVM影響較小。
要理解這個問題首先要理解JVM的內存分配。
首先我們看JVM的內存劃分:
image.png
主流GC的中,GC要么是Partial GC要么是Full GC:

  • Partial GC:并不收集整個GC堆的模式
    • Young GC:只收集young gen的GC
    • Old GC:只收集old gen的GC。只有CMS的concurrent collection是這個模式
    • Mixed GC:收集整個young gen以及部分old gen的GC。只有G1有這個模式
  • Full GC:收集整個堆,包括young gen、old gen、perm gen(如果存在的話)等所有部分的模式。

所以內存回收的粒度是比較大的,對于mimalloc并非像C++和Python那么敏感。這個影響跟G1的-XX:MaxGCPAuseMillS參數也有關系。如果這個jvm參數設置的太低的話,就會導致每次G1 回收的內存很少,受到的底層回收算法影響更大。
更多的關于GC的細節,可以參考下面的簡單聊聊GC場景下的內存釋放。
那么什么時候知道glibc對JVM產生了影響呢?通過RSS(進程駐留內存)來看:
image.png

內存增長模型

虛擬地址空間由地址總線寬度決定:

64位linux進程虛擬地址空間的內存增長模型如下所示:
image.png
思考題2: NIO bytebuffer分配的內存屬于堆內內存還是堆外內存?屬于user space還是kernal space?

答案:既可能是堆內內存也可能是堆外內存,既可能屬于user space也可能屬于kernal space。
image.png

虛擬地址空間、brk和mmap

分配小于128k內存時虛擬地址空間的情況
image.png
分配內存大于128k時的情況:
image.png
brk分配的內存需要等到高地址內存釋放以后才能釋放(例如,在B釋放之前,A是不可能釋放的,這就是內存碎片產生的原因),而mmap分配的內存可以單獨釋放。
mmap函數的作用就是分配/映射一段虛擬地址空間:
image.png

這兩種方式分配的都是虛擬內存,沒有分配物理內存。在第一次訪問已分配的虛擬地址空間的時候,發生缺頁中斷,操作系統負責分配物理內存,然后建立虛擬內存和物理內存之間的映射關系(寫時復制)。
mmap能解決那些性能問題?

  1. 用戶態到內核態的過程中,內存拷貝問題
  2. 內核態把臟數據寫回到塊設備的過程中,內存拷貝的問題
  3. 4K對齊問題
  4. 零拷貝(實際上是通過映射)問題


通過下面的流程圖可以很直觀的明白mmap的作用:
image.png
image.png

思考題:

  1. swap space大小影響虛擬空間地址大小嗎?
  2. malloc調用的mmap會設置flags為MAP_ANONYMOUS嗎?也就是說malloc會映射到文件嗎?
  3. mmap什么時候回寫到文件?
  4. mmap在文件映射時導致的臟頁在回寫之后怎么再次標記為臟頁觸發回寫?為什么跟write不一樣?
  5. mmap在文件映射時物理內存+swap spcae不夠怎么辦?
  6. mmap怎么保證文件頁緩存一致性?

答案:

  1. 不會
  2. 不會
  3. image.png

dirty pages的物理頁可以通過address_space 中的Radix樹快速找到并且被pdflush回寫。
image.png
struct mm_struct?
struct mm_struct 包含所有與進程相關的內存區域。 The mm field of struct task_struct is a pointer to the struct mm_struct of the current process.
struct vm_area_struct?
A struct vm_area_struct is created at each mmap() call issued from user space. A driver that supports the mmap() operation must complete and initialize the associated struct vm_area_struct. The most important fields of this structure are:

  • vm_start, vm_end - the beginning and the end of the memory area, respectively (these fields also appear in /proc//maps);
  • vm_file - the pointer to the associated file structure (if any);
  • vm_pgoff - the offset of the area within the file;
  • vm_flags - a set of flags;
  • vm_ops - a set of working functions for this area
  • vm_next, vm_prev - the areas of the same process are chained by a list structure

TCB結構圖
image.png

  1. 回寫的頁會變成寫保護,寫會再次觸發缺頁

PTE中R/W位標志是否寫保護
image.png
為什么跟write不一樣?我們先看看write的過程:
image.png
根本原因當然是再次寫不能切換到內核態無法修改PTE,只能通過寫保護再次觸發寫時復制缺頁異常,標記為臟頁。

  1. mmap觸發的缺頁異常并不會一次將所有文件內容讀到內存中。

linux將缺頁異常分為幾種情況分別分配內存,包括PTE是否為空,是匿名映射還是文件映射、是讀文件還是寫文件、頁面是否換出、是否滿足COW等等情況。
如果是文件映射導致的缺頁異常,最終的調用是這樣的:

	//如果map_pages函數不為空并且fault_around_bytes有效,//map_pages就是之前講過的預讀的操作函數,fault_around_bytes控制預讀長度,一般64kif (vma->vm_ops->map_pages && fault_around_bytes >> PAGE_SHIFT > 1) {//調用do_fault_around預讀幾個頁的文件內容讀取到vmf->page,為了減少頁錯誤異常的次數ret = do_fault_around(vmf);if (ret)return ret;}

可以通過MADV_SEQUENTIAL來更激進地申請mmap內存,也可以通過MAP_POPULATE直接將文件全部加載到內存中,這也意味著內存會被更快的釋放。

  1. 內核態申請的PTE是共享的 PTE中的G位表示是否共享

ptmalloc

image.png
memory
應用地址空間,由RAM或swap提供
chunk
可以在應用中分配、在glibc中釋放或與相鄰chunk組合成較大范圍的小范圍內存。請注意,chunk是給定給應用的memory的包裝器。每個chunk存在于一個heap中,屬于一個arena。
heap
memory中的一個連續區域,它被細分為要分配的chunk。每個heap恰好屬于一個arena。
arena
一種在一個或多個線程之間共享的結構,其中包含對一個或更多heap的引用,以及這些heap中“空閑”的chunk的鏈表。分配給每個arena的線程將從該arena的空閑列表(bins)中分配內存。

chunk

image.png
使用中的chunk
1、heap中有chunk指針和mem指針 chunk指針指向chunk開始的地址;mem指針指向用戶內存塊開始的地址。
2、 p=0時,表示前一個chunk為空閑,prev_size才有效
3、p=1時,表示前一個chunk正在使用,prev_size無效 p主要用于內存塊的合并操作;ptmalloc 分配的第一個塊總是將p設為1, 以防止程序引用到不存在的區域
4、M=1 為mmap映射區域分配;M=0為heap區域分配
5、 A=0 為主分配區分配;A=1 為非主分配區分配。
空閑的chunk
1、當chunk空閑時,其M狀態是不存在的,只有AP狀態,
2、原本是用戶數據區的地方存儲了四個指針,
指針fd指向后一個空閑的chunk,而bk指向前一個空閑的chunk,malloc通過這兩個指針將大小相近的chunk連成一個雙向鏈表。
在large bin中的空閑chunk,還有兩個指針,fd_nextsize和bk_nextsize,用于加快在large bin中查找最近匹配的空閑chunk。不同的chunk鏈表又是通過bins或者fastbins來組織的。

arenas和heaps

image.png
為了有效地處理多線程應用程序,glibc的malloc允許一次活動多個內存區域。因此,不同的線程可以訪問存儲器的不同區域,而不會相互干擾。這些記憶區域統稱為“arena”。有一個主mrena,即“main arena”,對應于應用程序的初始heap。malloc代碼中有一個靜態變量指向這個arena,每個arena都有一個下一個指針來鏈接其他arena。
隨著線程碰撞的壓力增加,glibc通過mmap創建了額外的arena來緩解壓力。arena的數量上限為系統中CPU數量的八倍,這意味著重線程應用程序仍會出現一些爭用,但代價是碎片會減少。
每個arena中都有一個mutex,用于控制對該arena的訪問。一些操作,例如訪問fastbins,可以使用原子操作來完成,并且不需要鎖定arena。所有其他操作都要求線程鎖定arena。對這個mutex的爭用是創建多個arena的原因——分配給不同arena的線程不需要相互等待。如果有爭用,線程將自動切換到未使用(未鎖定)的arenas。
每個arenas都從一個或多個堆中獲得內存。main arenas使用程序的初始堆(從.bss之后開始),可以使用mmap和brk分配內存。其它的arenas只能通過mmap為它們的堆分配內存,每個競技場都會跟蹤一個特殊的“頂部”chunk,這通常是最大的可用chunk,同時指向最近分配的heap。
總結:
1. 主分配區和非主分配區形成一個環形鏈表進行管理。
2. 每一個分配區利用互斥鎖使線程對于該分配區的訪問互斥。
3. 每個進程只有一個主分配區,也可以允許有多個非主分配區。
4. ptmalloc根據系統對分配區的爭用動態增加分配區的大小
5. 主分配區可以使用brk和mmap來分配,而非主分配區只能使用mmap來映射內存塊
6. 申請小內存時會產生很多內存碎片,ptmalloc在整理時也需要對分配區做加鎖操作

bins

為了避免頻繁的系統調用,應用free的內存塊,ptmalloc會根據size和歷史存儲在不同的bins中。
image.png

fast bins

fast bins是bins的高速緩沖區,大約有10個定長隊列。每個fast bin都記錄著一條free chunk的單鏈表(稱為binlist ,采用單鏈表是出于fast bin中鏈表中部的chunk不會被摘除的特點),增刪chunk都發生在鏈表的前端。
fastbin中的chunks可以根據需要移動到其他bins中。fast bins 記錄著大小以8字節遞增的bin鏈表。當用戶釋放一塊不大于max_fast(默認值64B)的chunk的時候,會默認會被放到fast bins上。當需要給用戶分配的 chunk 小于或等于 max_fast 時,malloc 首先會到fast bins上尋找是否有合適的chunk,除非特定情況,兩個毗連的空閑chunk并不會被合并成一個空閑chunk。不合并可能會導致碎片化問題,但是卻可以大大加速釋放的過程。

image.png

unsorted bins

unsorted bin 的隊列使用 bins 數組的第一個,是bins的一個緩沖區,加快分配的速度。當用戶釋放的內存大于max_fast或者fast bins合并后的chunk都會首先進入unsorted bin上。unsorted bins無尺寸限制,任何大小chunk都可以添加進這里。unsorted bins的設計主要是為了一個最近釋放的復用。
用戶malloc時,如果在 fast bins 中沒有找到合適的 chunk,則malloc 會先在 unsorted bin 中查找合適的空閑 chunk,如果沒有合適的bin,ptmalloc會將unsorted bin上的chunk放入bins上,然后到bins上查找合適的空閑chunk。

small bins

大小小于512字節的chunk被稱為small chunk,而保存small chunks的bin被稱為small bin。數組從2開始編號,前64個bin為small bins,small bin每個bin之間相差8個字節,同一個small bin中的chunk具有相同大小。每個small bin都包括一個空閑區塊的雙向循環鏈表(也稱binlist)。
free掉的chunk添加在鏈表的前端,而所需chunk則從鏈表后端摘除。兩個毗連的空閑chunk會被合并成一個空閑chunk。合并消除了碎片化的影響但是減慢了free的速度。分配時,當samll bin非空后,相應的bin會摘除binlist中最后一個chunk并返回給用戶。在free一個chunk的時候,檢查其前或其后的chunk是否空閑,若是則合并,也即把它們從所屬的鏈表中摘除并合并成一個新的chunk,新chunk會添加在unsorted bin鏈表的前端。

large bins

大小大于等于512字節的chunk被稱為large chunk,而保存large chunks的bin被稱為large bin,位于small bins后面。large bins中的每一個bin分別包含了一個給定范圍內的chunk,其中的chunk按大小遞減排序,大小相同則按照最近使用時間排列。
兩個毗連的空閑chunk會被合并成一個空閑chunk。
分配時,遵循原則“smallest-first , best-fit”,從頂部遍歷到底部以找到一個大小最接近用戶需求的chunk。一旦找到,相應chunk就會分成兩塊User chunk(用戶請求大小)返回給用戶。Remainder chunk(剩余大小添加到unsorted bin。free時和small bin 類似。

三種特殊chunks

有三種特殊chunks不會存儲到bins中:

  1. Top chunk
    top chunk相當于分配區的頂部空閑內存,當bins上都不能滿足內存分配要求的時候,就會來top chunk上分配。
    當top chunk大小比用戶所請求大小還大的時候,top chunk會分為兩個部分:User chunk(用戶請求大小)和Remainder chunk(剩余大小)。其中Remainder chunk成為新的top chunk。
    當top chunk大小小于用戶所請求的大小時,top chunk就通過sbrk(main arena)或mmap(thread arena)系統調用來擴容。
  2. mmaped chunk
    當分配的內存非常大(大于分配閥值,默認128K)的時候,需要被mmap映射,則會放到mmaped chunk上,當釋放mmaped chunk上的內存的時候會直接交還給操作系統。
    3、Last remainder chunk
    當在small bins中找不到合適的chunk,如果last remainder chunk的大小大于所需要的small chunk大小,last remainder chunk就會被分裂成兩個chunk,其中一個chunk返回給用戶,另一個chunk變成新的last remainder chunk。

tccache

線程會在thread local中記住用過的main arenas,如果這個arenas被占用,那么就會阻塞等待其釋放。
線程也有自己的cache,被稱為_tcache,這個塊大小受到限制,_分配時不需要使用arenas,而回退時需要使用arenas。
image.png

內存分配算法

image.png

  1. 如果在tcache中有一個合適的(精確匹配)塊,它就會返回給調用者。沒有則嘗試使用來自較大大小的bins的可用塊。
  2. 如果請求足夠大,則使用mmap()直接從操作系統請求內存。請注意,mmap的閾值是動態的,可以通過M_mmap_threshold參數修改,并且同時可以有多少mmap是有限制的。
  3. 如果合適的fastbin中有一個chunk,請使用它。如果有其他chunk可用,也可以預填充tcache。
  4. 如果適當的smallbin中有一個chunk,請使用它,可能還會在此處預填充tcache。
  5. 如果請求“很大”,花點時間把fast bins里的所有東西都拿走,然后把它們移到unsorted bins里,邊走邊合并。
  6. 開始從unsorted bins中取出塊,并將它們移到小/大的bins中,邊走邊合并(注意,這是代碼中唯一將塊放入小/大bins的地方)。如果看到一個合適大小的chunk,則使用它。
  7. 如果請求是“大”的,則搜索相應的大bin,然后依次搜索更大的bin,直到找到足夠大的chunk。
  8. 如果我們在fastbin中仍然有塊(這可能發生在“小”請求中),請合并這些塊并重復前兩個步驟。

內存釋放算法

free()調用并不會真正將內存返還到操作系統,而僅標記為可被應用程序重用。如果top chunk內存足夠大,那么可能會取消映射。

  1. 如果tcache中有空間,則將塊存儲在那里并返回。
  2. 如果區塊足夠小,請將其放入適當的fast bins中。
  3. 如果這個區塊是mmap的,就對它進行munmap。
  4. 查看此bins是否與另一個可用bins相鄰,如果相鄰則合并。
  5. 將區塊放在unsorted bins中,除非它現在是top trunk。
  6. 如果thunk足夠大,合并所有fastbin,然后如果頂部的thunk是否足夠大,將會在os中取消映射。出于性能原因,這一步驟可能會被推遲,并在malloc或其他調用期間發生。

簡單聊聊GC場景下的內存釋放

結合上面文章,主要是考慮GC一次回收的粒度問題。
以目前jdk默認的G1為例。
按照分代收集理論,新生代會比老年代有更頻繁的gc調用。

參考資料

https://ionutbalosin.com/2020/01/hotspot-jvm-performance-tuning-guidelines/
https://man7.org/linux/man-pages/man2/mmap.2.html
https://zhuanlan.zhihu.com/p/166576293
https://www.microsoft.com/en-us/research/uploads/prod/2019/06/mimalloc-tr-v1.pdf
https://zhuanlan.zhihu.com/p/658307892
https://openjdk.org/groups/hotspot/docs/RuntimeOverview.html#Thread%20Management|outline
https://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf
https://tldp.org/LDP/lki/lki-4.html
https://keys961.github.io/2019/04/10/Linux%E5%86%85%E6%A0%B8-%E9%A1%B5%E9%AB%98%E9%80%9F%E7%BC%93%E5%AD%98%E4%B8%8E%E9%A1%B5%E5%9B%9E%E5%86%99/
https://www.kernel.org/doc/gorman/html/understand/understand005.html
https://www.infradead.org/~mchehab/rst_conversion/filesystems/vfs.html

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

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

相關文章

Redis 數據的持久化 RDB、AOF、RDB + AOF、No persistence 各自優缺點

文章目錄 一、RDB (Redis Database)1.1 RDB 優勢1.2 RDB 缺點1.3 RDB 如何工作1.4 RDB配置1.5 開啟/關閉,RDB快照策略,save指令1.6 持久化硬盤文件,dbfilename指令1.7 持久化硬盤文件的存儲地址,dir指令 二、AOF (Append Only Fil…

leetcode:643. 子數組最大平均數 I(滑動窗口)

一、題目 鏈接:643. 子數組最大平均數 I - 力扣(LeetCode) 函數原型: double findMaxAverage(int* nums, int numsSize, int k) 二、思路 滑動窗口: 先計算數組前k個元素總和,作為第一個窗口,默…

vlog如何降低重復率

大家好,今天來聊聊vlog如何降低重復率,希望能給大家提供一點參考。 以下是針對論文重復率高的情況,提供一些修改建議和技巧: vlog如何降低重復率 Vlog作為一種流行的視頻日志形式,常常被人們用于記錄日常生活、分享經…

pta模擬題——7-34 刮刮彩票

“刮刮彩票”是一款網絡游戲里面的一個小游戲。如圖所示: 每次游戲玩家會拿到一張彩票,上面會有 9 個數字,分別為數字 1 到數字 9,數字各不重復,并以 33 的“九宮格”形式排布在彩票上。 在游戲開始時能看見一個位置上…

Lambda表達式規則,用法

Lambda表達式是JDK8新增的一種語法格式 1.作用 簡化匿名內部類的代碼寫法 Lambad用法前提:只能簡化函數式接口(一般加有Funcationallnterface)(有且僅有一個抽象方法)的匿名內部類 匿名內部類:(本質是對…

url轉pdf或者html轉pdf工具 — iText實現url轉pdf

url轉pdf或者html轉pdf工具 — iText實現url轉pdf 參考資料: https://kb.itextpdf.com/itext/can-i-generate-a-pdf-from-a-url-instead-of-from-a- http://www.micmiu.com/opensource/expdoc/itext-pdf-demo/ https://blog.51cto.com/u_16237557/7263784 iText&…

sensitive-word 敏感詞/臟詞開源工具-v.0.10.0-臟詞分類標簽支持

sensitive-word sensitive-word 基于 DFA 算法實現的高性能敏感詞工具。 創作目的 實現一款好用敏感詞工具。 基于 DFA 算法實現,目前敏感詞庫內容收錄 6W(源文件 18W,經過一次刪減)。 后期將進行持續優化和補充敏感詞庫&…

幾種常用的壓力測試工具

1. JMeter 官網: Apache JMeter簡介: Apache JMeter 是一個開源軟件,主要用于性能測試和壓力測試。它可以用來測試靜態和動態資源,如文件、Web服務、REST API等。下載與使用: 訪問官網下載安裝包。解壓安裝包并運行 JMeter。通過創建測試計劃來設置壓力…

2023年終總結-輕舟已過萬重山

自我介紹 高考大省的讀書人 白,隴西布衣,流落楚、漢。-與韓荊州書 我來自孔孟故里山東濟寧,也許是小學時的某一天,我第一次接觸到了電腦,從此對它產生了強烈的興趣,高中我有一個愿望:成為一名計…

設計模式再探——裝飾模式

目錄 一、背景介紹二、思路&方案三、過程1.裝飾模式簡介2.裝飾模式的類圖3.裝飾模式代碼4.裝飾模式,職責父類拆分的奧義5.裝飾模式,部件抽象類的無中生有 四、總結五、升華 一、背景介紹 最近公司在做架構模型的時候,涉及到裝飾模式的研…

html網頁設計 01marquee標簽廣告滾動(1)

<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><!-- scrollamount:數字越大&#xff0c;滾動越快direction:滾動方向滾動的類型behaior"slide",文字滾動到邊界后就會…

Python中的lambda匿名函數詳解以及三種經典使用場景

lambda匿名函數 匿名函數&#xff0c;顧名思義就是不需要具體定義函數名的函數。我們首先拋開復雜的定義&#xff0c;看兩個具體例子。 先看一個無參數函數的例子。假設我們需要一個return 1的函數&#xff0c;如果使用普通的函數定義方式&#xff0c;其代碼為&#xff1a; …

vuepress-----20、全文搜索

默認主題自帶的搜索, 只會為頁面的標題、h2、h3 以及 tags構建搜索索引。所以盡量將圍繞知識點的關鍵字體現到標題上。而 tags 更為靈活&#xff0c;可以把相關的能想到的關鍵字都配置到 tags 中&#xff0c;以方便搜索。 默認插件介紹 (opens new window) 默認主體配置 (ope…

電子秤ADC芯片CS1237技術資料問題合集

問題11&#xff1a;實際應用中&#xff0c;多個稱重傳感器應該怎么與ADC連接&#xff1f; 解答&#xff1a;如果傳感器是測量同一物體&#xff08;例如&#xff1a;廚房垃圾處理器&#xff09;&#xff0c;一般建議使用并聯的方式。則相同類型的信號線連接在一起。對于傳感器的…

C語言指針基礎題(一)

目錄 例題一題目解析答案 例題二題目解析答案 例題三題目解析答案 例題四題目解析答案 例題五題目解析答案 例題六題目解析答案 例題七題目解析答案 感謝各位大佬對我的支持,如果我的文章對你有用,歡迎點擊以下鏈接 &#x1f412;&#x1f412;&#x1f412; 個人主頁 &#x…

C++ 教程 - 01 基礎篇

文章目錄 C介紹環境配置第一個cpp程序案例練習 變量常量關系運算符邏輯運算符條件運算符位運算符類型轉換分支循環程序調用綜合案例 C介紹 基于C語言&#xff0c;繼承了C的所有語法&#xff1b; 靜態類型語言&#xff0c;需要先編譯&#xff0c;再執行&#xff1b; 貼近底層硬…

雪花算法:分布式系統的關鍵藝術

導言 在探索分布式系統的奧秘時&#xff0c;我們經常遇到一個看似簡單卻極其關鍵的挑戰&#xff1a;如何高效、可靠地生成唯一的標識符&#xff08;ID&#xff09;。這不僅是技術的問題&#xff0c;更是一種藝術。讓我們深入探討雪花算法&#xff08;Snowflake Algorithm&…

windows下分卷解壓文件

我的文件是這樣的&#xff1a; 存放路徑為&#xff1a;C:\Users\Luli_study\MICCAI_MMAC\fudanuniversity\DDR dataset 首先要進入分卷文件的目錄cd&#xff1a; 第一步&#xff1a;cd /path/o/分卷問文件目錄 第二步&#xff1a; 執行之后的結果(紅色框出來的)&#xff1a; …

?functools --- 高階函數和可調用對象上的操作?

源代碼: Lib/functools.py functools 模塊應用于高階函數&#xff0c;即參數或&#xff08;和&#xff09;返回值為其他函數的函數。 通常來說&#xff0c;此模塊的功能適用于所有可調用對象。 functools 模塊定義了以下函數: functools.cache(user_function) 簡單輕量級未綁…

Vellum —— Fluid

目錄 Vellum fluids setups Fluid tips and troubleshooting Fluid phases Vellum fluids and soft bodies Vellum fluid vs FLIP fluid Vellum fluids setups Vellum fluid solver是基于粒子流體的解算框架&#xff0c;被完全集成到了Vellum動力學系統&#xff08;可與gr…