再次盤點自有函式,包含新加入的更新服務。完整範圍、取捨、基準與重跑方式見第二次函式檢查報告。
- 2,000 個不支援檔案的掃描配置量由 690 KB 降至 274 KB;先判斷檔名,再為需要的項目組合路徑。
- 64 段 HLS 清單解析由 96.7 KB 降至 28.5 KB 配置,保留原有單行限制、格式與錯誤行為。
- 更新輪詢使用精簡快照,重用完整發行資訊;相同下載/更新狀態不再替換 React state。
- 4,999 列含空白數值的表格排序由 4.535 ms 降至 0.724 ms;已排序數值欄位使用無排序工作區的快速路徑。
前端 161 項、Go 205 項一般測試及 3 個 fuzz 種子套件通過;race、Go vet、TypeScript/Vite、Wails production 編譯及 macOS 12 arm64 目標檢查通過。前端 JSX/CSS 與本輪修改前一致。上述為受控函式基準,非整體 App 或長時間 RSS 量測。
本輪完成自有 Go、前端及建置工具的函式盤點,維持 UI、操作、功能與認證方式。完整範圍、函式清單說明、量測及重跑方式見函式檢查報告。
- 掃描及項目建立共用副檔名結果;壓縮檔建樹只為新節點建立路徑。5,000 筆共用目錄的建樹基準由 2.105 ms/60,052 次配置降至 0.937 ms/59 次配置。
- 換行正規化使用單一輸出配置;UTF-16 直接解碼,省去 code unit 與 rune 中間資料。代表性 ASCII/中文輸入配置量分別由 2.25/1.87 MB/op降至 0.180/0.336 MB/op。
- HLS 下載共用分段緩衝,線性選流並精簡屬性解析;256 個分段的純複製配置由 64.01 MiB/op降至 268 KiB/op。
- 音訊預計算頻譜位置並重用振幅陣列,72 柱計算由 5.77 µs降至 1.78 µs;字幕改為單次選出最佳候選。
- 主視窗只收集必要的選取 ID;相同文件的上色結果在元件內重用。1,000 行程式碼再次渲染的函式基準由 14.83 ms降至 1.28 ms。
前端 146 項、Go 186 項一般測試及 2 個 fuzz 種子套件全部通過;Go race、額外文字 fuzz、TypeScript/Vite、Go vet、原生編譯及 macOS 12 目標檢查通過。App/播放器 JSX 與 Canvas 繪圖結果對照原版保持一致。
上述數據是受控函式基準,配置量不是常駐記憶體;不包含實際網路下載、磁碟掃描或原生 WebView 的長時間 RSS。新增工作區的保留時間及完整驗證界限列於報告。
- 虛擬網格只掛載可視列及前後兩列,保留「載入更多/全部載入」與跨捲動選取。
- 前端縮圖 LRU 同時限制 200 筆及 16 MiB(依 UTF-16 字串長度保守估計);未開始的離屏請求直接移除,最多同時 3 個後端請求。
- 後端縮圖直接串流解碼,只暫存讀取尺寸所需的前綴;同時解碼的總像素不超過 5,000 萬。
- 磁碟縮圖使用 LRU 索引;每次寫入維持最多 1,200 筆、256 MiB,只在初始化掃描目錄。外部刪除快取時同步移除索引。
- 縮圖版本包含來源大小與修改時間;macOS 另比對 inode 與 change time。解碼期間來源變更時不寫入舊版本快取;快取讀取在同一 FD 上限制最多 16 MiB。
- 影音解壓及轉檔快取比對來源檔案識別、大小、修改時間;來源更新時重建,已開啟的舊讀取器仍可完成讀取。
- 媒體清理先取消準備與複製,再等待項目鎖釋放;HTTP 只持鎖至成功開檔,串流讀取不占用準備鎖。
- 像素預算不是程序 RSS 上限:解碼器工作區、16-bit 圖片及 GC 尚未回收的物件仍會占用記憶體。仍使用 Go 完整解碼,尚未加入平台限定的降採樣解碼器。
LoadImage* 的 ImagePayload.dataUri 可為 /image/<id>?v=... 本機網址。保留欄位名稱以維持前端結構;不要假設一定是 Base64。
本機圖片由 HTTP 串流傳輸,保留 128 MiB 檔案與 5,000 萬像素限制,GET/HEAD/Range 與 ETag。端點只接受已註冊的圖片 ID。壓縮檔圖片仍有完整驗證緩衝區,最多並行 2 筆;原圖不再經由 Wails 傳輸 Base64。
前端只解碼目前顯示的圖片,切圖取消舊要求,背景僅預備相鄰圖片的網址/標頭。剪貼簿仍可輸出 PNG,只有文字備援時才轉回 Data URI。
- ZIP:LRU 最多 4 個中央目錄索引;每個最多 20,000 個項目與約 8 MiB 的標頭資料估計值。超限時不保留索引。
- TAR/TGZ:最多 2 份、每份最多 256 MiB 的私有暫存內容與 20,000 個索引項目。第一次讀取建立索引會多花時間與磁碟 I/O,後續以位移讀取;超限或稀疏檔案回到原串流方式。暫存檔不依壓縮檔中的路徑解壓至目錄。
- 大小、修改時間或檔案識別改變時快取失效;清空圖庫及結束應用程式會清理快取。使用中的 reader 關閉後才釋放其資源。
展開狀態與選取獨立儲存,不觸發整棵樹的 JSON 寫入。掃描約每 100 ms 批次更新畫面,同批結果只遍歷一次樹;未變更分支保留原參考。忽略未支援的檔案時不額外取得檔案資訊。
本輪繼續保留 UI、操作、功能與認證方式,沿用上一輪修改。
- 目錄掃描改為優先/一般兩個 FIFO 佇列,路徑只分類一次,避免每次加入子目錄後重新排序全部待掃描路徑。以固定 256 筆的分塊保存,取出後清除該路徑參照,清空的區塊可回收。Finder 指定路徑仍優先,各群組順序、進度與取消檢查維持不變。
- 工作區無篩選時直接複製清單,保留每次篩選結果的新陣列身分;搜尋改為欄位逐一短路比較,不建立每筆欄位陣列,也不保存持久搜尋字串快取。
- 零選取時不再建立整個圖庫的有效 ID 集合;非空選取只保留與選取相交的 ID。範圍/全選不先建立中間 ID 陣列,批次刪除以集合查詢取代逐筆 includes,保留選取插入順序及部分失敗行為。
- CSV/TSV 使用重用的語系比較器,保留原有數字優先及自然排序。沒有排序的搜尋只保留前 1,000 筆,在第 1,001 筆符合時顯示原本的截斷提示;需要排序時仍處理全部匹配列。已由篩選產生的新陣列可直接排序,避免額外複製。
- 後端在大小提示為 1 MiB 以下時預配置讀取緩衝。提示只影響容量,不決定讀取長度;仍完整讀至 EOF,保留大小哨兵、ZIP CRC、取消與檔案大小失準處理。未知或較大提示使用原有標準讀取方式,避免預先配置大量記憶體。
受控基準:
| 情境 | 調整前 | 調整後 |
|---|---|---|
| 2,500 待掃描目錄、帶優先目標,純佇列管理 | 801 ms | 0.465 ms |
| 50,000 筆無篩選清單時間 | 0.888 ms | 0.049 ms |
| 同上,暫時 heap 增量 | 1.24 MB | 0.40 MB |
| 50,000 筆搜尋無匹配,暫時 heap 增量 | 15.32 MB | 8.41 MB |
| 空選取重新整理,暫時 heap 增量 | 3.02 MB | 約 1 KB |
| 10,000 個選取刪除 5,000 個的集合更新 | 62.60 ms | 0.500 ms |
| 4,999 × 24 表格,文字排序 | 107.51 ms | 9.58 ms |
| 同一表格,大量匹配、無排序篩選的 heap 增量 | 5.17 MB | 1.07 MB |
| 1 MiB 一般項目讀取配置 | 2.23 MB/op | 1.06 MB/op |
| 128 KiB 縮圖快取讀取配置 | 303 KB/op | 141 KB/op |
| 1 MiB 圖庫快取讀取配置 | 3.28 MB/op | 2.11 MB/op |
取捨與量測範圍:批次刪除增加約 67 KiB 暫時 heap,以換取線性集合查詢;40,000 目錄、無優先目標的佇列基準亦增加約 2.1 MB 暫時 heap,避免反覆搬移陣列。分塊在出列後釋放路徑及空區塊,不保留完整歷史。這些 heap 差額受 Node GC 影響,並非精確配置總量或原生 App RSS;佇列基準不含磁碟掃描及畫面更新,不能推論實際掃描等比例加速。8 MiB 讀取配置維持原路徑,約 17.06 MB/op。
重跑本輪基準:
cd frontend
node --expose-gc benchmarks/scan-queue.mts
node --expose-gc --max-semi-space-size=256 benchmarks/workspace.mts
node --expose-gc benchmarks/structured-table.mts
cd ..
GOTOOLCHAIN=go1.26.6 go test ./internal/app -run '^$' -bench 'BenchmarkBounded' -benchmem -benchtime=300ms本輪驗證:
- 新增 19 項一般回歸測試(前端 15、Go 4)。前端 131 項、Go 178 項一般測試及 1 個 fuzz 種子套件全部通過,無跳過;Go 使用 race detector,internal/app statement coverage 73.8%。
- TypeScript/Vite production build、Go vet、desktop/production 原生編譯通過,arm64 最低 macOS 版本維持 12.0。App JSX 與修改前逐段比對一致。
- 掃描驗證一般 FIFO、Finder 優先、略過封存節點、取消及分塊邊界;篩選驗證 Unicode、結果身分、選取順序、部分失敗及重複結果失效;表格結果逐項對照原版;讀取包含大小提示失準、尾端 CRC 及最後一次讀取的取消。
- 修改前保留 .bak,完成後清除本輪備份、建置/測試輸出及驗證專用 Go 快取。保留既有 App/DMG、模型與上一輪未提交修改;未同步 GitHub。
驗證界限:未量測原生 WebView 長時間 RSS;FFmpeg/ffprobe 回歸採受控替身,未重新進行原生介面人工操作或完整發行封裝驗證。基準與一般配置最佳化不構成整體 App 效能保證。
本次維持 UI、操作、功能、格式支援及安全限制;只調整內部資料整理與工作區重用。
- 圖庫更新採延遲複製,未變動的 images/children 不建立替代陣列;批次搬移只遍歷一次樹,每個目的地排序一次。成功/失敗回報、選取清理及同名穩定排序保持原有語義。
- 顯示樹保留未變動分支,WeakMap 快取可見節點與分類統計。節點更新必須維持 immutable;快取以弱鍵保存,不阻止已丟棄樹被 GC 回收。
- 工作區維持根節點優先的順序,導覽維持子節點優先的順序。收集結果直接追加,不再每層複製整份子樹陣列;根目錄清單共用既有結果。
- 摺疊節點的選取標記一次檢查所有選取 ID。圖片預取仍依 +1、−1、+2、−2 的圖片順序,只收集附近項目,不再每次切圖建立完整導覽與篩選陣列。
- 檔名排序直接比較小寫 rune,避免每次比較建立兩個小寫字串;保持 strings.ToLower 的 Unicode、無效 UTF-8 與穩定排序行為。
- 重複內容偵測以輸入下標保存候選,只有相同大小時才建立候選陣列;同次操作共用 32 KiB 雜湊讀取緩衝,確認重複後才建立回傳項目。
- 磁碟縮圖快取命中時移動原 LRU 節點,更新大小差額,不再移除後重新配置節點。PNG 壓縮工作區可重用;使用後清除縮圖像素與輸出 buffer 的參照,閒置工作區仍可由 GC 回收。原圖已符合縮圖尺寸時直接複製,省去雙線性縮放的中間陣列;代表性像素格式的 PNG 輸出與原流程逐 byte 相同。
受控基準(同一測試資料;數值取代表性量測,時間會受背景負載影響):
| 情境 | 調整前 | 調整後 |
|---|---|---|
| 62,480 筆圖庫資料整理時間 | 7.52 ms | 3.87 ms |
| 同上,暫時 heap 增量 | 32.89 MB | 12.60 MB |
| 40,000 項目圖庫批次搬移 100 項 | 28.16 ms | 1.50 ms |
| 20,000 個不同大小項目去重配置 | 5.82 MB/op | 1.18 MB/op |
| 256 個同大小檔案去重配置 | 8.87 MB/op | 0.385 MB/op |
| 5,000 個 ASCII/Unicode 名稱排序配置 | 4.93/7.40 MB/op | 232 B/op |
| 256×256 無須縮放的縮圖時間 | 4.82 ms | 4.05 ms |
| 同上,配置量 | 4.26 MB/op | 1.33 MB/op |
| 640×480 縮至 280 的配置量 | 7.27 MB/op | 6.99 MB/op |
| 縮圖 LRU 命中維護配置(不含磁碟 I/O) | 72 B/op | 0 B/op |
Node heap 增量是強制 GC 後呼叫前後的近似差額,不是精確配置總量或程序 RSS;部分無命中操作主要減少配置,未保證每次執行較快。Go B/op 是基準記錄的配置量。這些結果不代表整體 App 等比例加速或常駐記憶體降幅。
可重跑:
cd frontend
node --expose-gc benchmarks/library-view.mts
node --expose-gc --max-semi-space-size=256 benchmarks/library-tree.mts
cd ..
GOTOOLCHAIN=go1.26.6 go test ./internal/app -run '^$' -bench 'Benchmark(LibraryNameSort|DuplicateDetection|ThumbnailRenderReuse|ThumbnailUnscaledReuse|ThumbnailDiskCacheHit)' -benchmem -benchtime=300ms本輪驗證:
- 前端 116 項測試通過;Go 174 項一般測試及 1 個 fuzz 種子套件通過,無跳過,使用 Go 1.26.6 race detector。internal/app statement coverage 73.6%。
- 本輪新增 18 項一般回歸測試及 1 個 fuzz 測試;排序另以 10 秒、約 10 萬組 fuzz 輸入比對原有 strings.ToLower 行為。
- TypeScript/Vite production build、Go vet、desktop/production 原生編譯通過,最低 macOS 版本維持 12.0。
- App 的 JSX 結構逐段比對未變;不同圖庫形狀的可見樹、兩種遍歷順序、分類統計、祖先 ID、選取、預取及批次搬移均與原行為比對。
- 縮圖涵蓋 6 種 PNG 像素格式、JPEG/GIF、透明與不透明圖片、多個尺寸及 12 個並行工作,對照原縮放流程輸出。
- 修改前建立 .bak;完成後清除本輪備份、測試輸出及驗證專用 Go 快取。未改 UI 樣式、認證或建置流程,未同步 GitHub。
驗證界限:這些基準沒有量測原生 WebView 長時間 RSS;PNG 工作區重用減少累計配置,閒置工作區可能存活至後續 GC。FFmpeg/ffprobe 回歸使用受控替身,未重新完成原生介面人工操作或發行包簽章驗證。
npm --prefix frontend run buildnpm --prefix frontend test:46 項通過,包含虛擬網格、縮圖容量與取消、圖片傳輸取消、批次樹合併、深層 JSON、移動來源對應、操作釋放、音訊/字幕非同步取消及 FFmpeg 建置前檢查。go test -race ./...:111 項通過,包含跨磁碟搬移與取消、媒體生命週期、圖片 HTTP 端點、安全限制、ZIP/TAR 快取失效、使用中淘汰與解碼預算測試。- Chromium + 模擬 Wails 圖庫:10,000 張圖片,1500×950 視窗頂端 18 張卡片、底端 16 張;選取、來回捲動、篩選、縮放視窗通過,沒有 pageerror。後端縮圖呼叫峰值 3。展開目錄後完整圖庫寫入次數不變。這不是 macOS 原生 WebView 的 RSS 量測。
- Apple M4、Go 1.26.4,5,000 個 ZIP 項目、讀取最後一項的合成微型基準:重新開啟/搜尋約 490 µs、1,272,527 B/op;索引命中約 3.09 µs、737 B/op。這僅反映暖快取查找,不能推論整個程式快 158 倍。
重跑 ZIP 基準:
go test ./internal/app -run '^$' -bench BenchmarkZIPEntryLookup -benchmem -benchtime=300ms3D 渲染維持既有材質、畫質及滑鼠操作。格式解析器只在選取對應模型時載入;模型輸入優先直接填入單一緩衝區,整數百分比改變時才更新進度。共用材質只檢查一次,靜態場景完成後固定世界矩陣;畫布尺寸與像素倍率相同時不重新配置。取消預覽時立即清空場景集合,延遲完成的貼圖也會回收。
在 frontend 執行:
node --expose-gc benchmarks/model-preview.mts| 合成案例 | 修改前 | 修改後 |
|---|---|---|
| 64 MiB 串流輸入的 ArrayBuffer 用量 | 約 128 MiB | 約 68 MiB |
| 相同輸入的進度通知 | 1,024 次 | 101 次 |
| 5,000 個共用幾何/材質網格的檢查中位數 | 4.13 ms | 0.82 ms |
基準保留修改前的讀取與檢查實作作為比較;輸入每區塊 64 KiB,並定期允許 GC,模型檢查則先暖機、量測五輪後取中位數。記憶體只衡量輸入 ArrayBuffer,不包含整個 App、WebKit、模型解析、貼圖解碼或 GPU;時間與模型內容及硬體有關,不能推算整體 App 的等比例加速。
13 組原生 macOS WebKit 比較涵蓋七種格式、點雲、不受光材質、正常與缺少貼圖及受限資源;修改前後畫素一致,旋轉、平移、縮放、重設與快速取消通過。正式打包另驗證 HTTP 與 wails:// 的按需載入及相同操作。