Files
MyGoNavi/internal/app/memory_reclaim.go
Syngnat ee78b9b57c ️ perf(import-export): 降低大文件导入导出内存占用
- xlsx 导出改为临时 sheet 加 zip 直写,避免整包缓冲到内存
- xlsx 导入改为 zip xml 流式解析,并将 shared strings 落到临时文件
- 大任务完成后按行数和文件大小阈值触发内存回收
- 补充导入导出流式链路的测试与基准覆盖
2026-06-18 09:21:01 +08:00

80 lines
1.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package app
import (
"os"
"runtime"
"runtime/debug"
"strings"
"sync/atomic"
"time"
"GoNavi-Wails/internal/logger"
)
const (
fileTransferMemoryTrimRowsThreshold int64 = 100000
fileTransferMemoryTrimFileSizeThreshold int64 = 64 * 1024 * 1024
fileTransferMemoryTrimMinInterval = 3 * time.Second
)
var (
fileTransferMemoryTrimRunning atomic.Bool
fileTransferMemoryTrimLastAt atomic.Int64
runFileTransferMemoryTrimAsync = func(fn func()) {
go fn()
}
fileTransferMemoryTrimFn = func() {
runtime.GC()
debug.FreeOSMemory()
}
)
func maybeReleaseFileTransferMemory(reason string, rows int64, filePath string) {
if !shouldReleaseFileTransferMemory(rows, filePath) {
return
}
if !fileTransferMemoryTrimRunning.CompareAndSwap(false, true) {
return
}
runFileTransferMemoryTrimAsync(func() {
defer fileTransferMemoryTrimRunning.Store(false)
if delay := nextFileTransferMemoryTrimDelay(); delay > 0 {
time.Sleep(delay)
}
logger.Infof("大文件导入导出任务结束尝试回收进程内存reason=%s rows=%d file=%s", strings.TrimSpace(reason), rows, strings.TrimSpace(filePath))
fileTransferMemoryTrimFn()
fileTransferMemoryTrimLastAt.Store(time.Now().UnixNano())
})
}
func shouldReleaseFileTransferMemory(rows int64, filePath string) bool {
if rows >= fileTransferMemoryTrimRowsThreshold {
return true
}
filePath = strings.TrimSpace(filePath)
if filePath == "" {
return false
}
info, err := os.Stat(filePath)
if err != nil {
return false
}
return info.Size() >= fileTransferMemoryTrimFileSizeThreshold
}
func nextFileTransferMemoryTrimDelay() time.Duration {
lastUnixNano := fileTransferMemoryTrimLastAt.Load()
if lastUnixNano <= 0 {
return 0
}
elapsed := time.Since(time.Unix(0, lastUnixNano))
if elapsed >= fileTransferMemoryTrimMinInterval {
return 0
}
return fileTransferMemoryTrimMinInterval - elapsed
}