diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index 8e02b8d..9594af6 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -11,6 +11,7 @@ import ( "github.com/engigu/baihu-panel/internal/logger" "github.com/engigu/baihu-panel/internal/router" "github.com/engigu/baihu-panel/internal/services" + "github.com/engigu/baihu-panel/internal/utils" "github.com/gin-gonic/gin" ) @@ -23,12 +24,15 @@ type App struct { func New() *App { app := InitBasic() app.initRouter() + // 初始化完成后回收一次内存 + utils.FreeMemory() return app } // InitBasic 初始化基础环境(配置和数据库),不启动后台服务和路由 func InitBasic() *App { app := &App{} + utils.InitRuntime() app.initConfig() app.initDatabase() return app diff --git a/internal/services/tasks/tiny_log.go b/internal/services/tasks/tiny_log.go index f30af34..a785f3e 100644 --- a/internal/services/tasks/tiny_log.go +++ b/internal/services/tasks/tiny_log.go @@ -3,7 +3,6 @@ package tasks import ( "bufio" "bytes" - "compress/zlib" "encoding/base64" "io" "os" @@ -225,15 +224,18 @@ func (l *TinyLog) CompressAndCleanup() (string, error) { // 创建压缩输出缓冲区 var buf bytes.Buffer b64Writer := base64.NewEncoder(base64.StdEncoding, &buf) - zlibWriter := zlib.NewWriter(b64Writer) + + // 使用 Pool 优化压缩 + zw := utils.GetZlibWriter(b64Writer) + defer utils.PutZlibWriter(zw) // 流处理: 文件 -> Zlib -> Base64 -> 缓冲区 - if _, err := io.Copy(zlibWriter, f); err != nil { + if _, err := io.Copy(zw, f); err != nil { return "", err } // 关闭写入器以刷新数据 - if err := zlibWriter.Close(); err != nil { + if err := zw.Close(); err != nil { return "", err } if err := b64Writer.Close(); err != nil { diff --git a/internal/utils/compress.go b/internal/utils/compress.go index d86e128..e6b8009 100644 --- a/internal/utils/compress.go +++ b/internal/utils/compress.go @@ -5,21 +5,43 @@ import ( "compress/zlib" "encoding/base64" "io" + "sync" ) +var zlibWriterPool = sync.Pool{ + New: func() interface{} { + return zlib.NewWriter(io.Discard) + }, +} + +// GetZlibWriter 从对象池中获取 zlib 写入器 +func GetZlibWriter(w io.Writer) *zlib.Writer { + zw := zlibWriterPool.Get().(*zlib.Writer) + zw.Reset(w) + return zw +} + +// PutZlibWriter 将 zlib 写入器还回对象池 +func PutZlibWriter(zw *zlib.Writer) { + zlibWriterPool.Put(zw) +} + // CompressToBase64 compresses data using zlib and encodes to base64 func CompressToBase64(data string) (string, error) { if data == "" { return "", nil } var buf bytes.Buffer - zw := zlib.NewWriter(&buf) + zw := GetZlibWriter(&buf) + defer PutZlibWriter(zw) + if _, err := zw.Write([]byte(data)); err != nil { return "", err } if err := zw.Close(); err != nil { return "", err } + return base64.StdEncoding.EncodeToString(buf.Bytes()), nil } diff --git a/internal/utils/runtime.go b/internal/utils/runtime.go new file mode 100644 index 0000000..85eb7c5 --- /dev/null +++ b/internal/utils/runtime.go @@ -0,0 +1,41 @@ +package utils + +import ( + "os" + "runtime" + "runtime/debug" + "strconv" + + "github.com/engigu/baihu-panel/internal/logger" +) + +// InitRuntime 设置运行时内存和性能优化参数 +func InitRuntime() { + // 从环境变量或配置读取 GOGC + if gogc := os.Getenv("GOGC"); gogc == "" { + // 默认设为 80,比 100 更激进一点,减少 RSS 峰值 + debug.SetGCPercent(80) + } + + // 从环境变量读取 GOMEMLIMIT (Go 1.19+) + // 建议用户在系统层面设置,例如 BH_MEM_LIMIT=256MiB + if memLimit := os.Getenv("BH_MEM_LIMIT"); memLimit != "" { + // 这里可以解析一下单位,但简单处理可以直接读取字节 + if limit, err := strconv.ParseInt(memLimit, 10, 64); err == nil { + debug.SetMemoryLimit(limit) + logger.Infof("[Runtime] 已设置内存上限: %d 字节", limit) + } + } + + // 打印当前运行时信息 + logger.Infof("[Runtime] CPU 核心数: %d, Goroutine 数量: %d", runtime.NumCPU(), runtime.NumGoroutine()) +} + +// FreeMemory 显式触发内存回收,释放物理资源给 OS +// 仅建议在执行了超大批量任务或处理了大型文件后调用 +func FreeMemory() { + // 触发 GC + runtime.GC() + // 尽可能将内存归还 OS + debug.FreeOSMemory() +}