From b4a761d0717ac696708d3f7269d0d4634cf853f9 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 7 Feb 2026 11:49:58 +0800 Subject: [PATCH] :zap: Reduce the memory usage when exporting documents containing numerous references https://github.com/siyuan-note/siyuan/issues/16982 Signed-off-by: Daniel <845765@qq.com> --- kernel/model/export.go | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/kernel/model/export.go b/kernel/model/export.go index 9929efacb..70dbe32fb 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -2241,10 +2241,10 @@ func ExportMarkdownContent(id string, refMode, embedMode int, addYfm, fillCSSVar return } -func exportMarkdownContent(id, ext string, exportRefMode int, defBlockIDs []string, singleFile bool, treeCache map[string]*parse.Tree) (tree *parse.Tree, exportedMd string, isEmpty bool) { - tree, err := loadTreeWithCache(id, treeCache) +func exportMarkdownContent(rootID, ext string, exportRefMode int, defBlockIDs []string, singleFile bool, treeCache map[string]*parse.Tree) (tree *parse.Tree, exportedMd string, isEmpty bool) { + tree, err := loadTreeWithCache(rootID, treeCache) if err != nil { - logging.LogErrorf("load tree by block id [%s] failed: %s", id, err) + logging.LogErrorf("load tree by block id [%s] failed: %s", rootID, err) return } @@ -2263,7 +2263,7 @@ func exportMarkdownContent(id, ext string, exportRefMode int, defBlockIDs []stri } } - exportedMd = exportMarkdownContent0(id, tree, "", false, false, false, + exportedMd = exportMarkdownContent0(rootID, tree, "", false, false, false, ext, exportRefMode, Conf.Export.BlockEmbedMode, Conf.Export.FileAnnotationRefMode, Conf.Export.TagOpenMarker, Conf.Export.TagCloseMarker, Conf.Export.BlockRefTextLeft, Conf.Export.BlockRefTextRight, @@ -3066,8 +3066,21 @@ func resolveFootnotesDefs(refFootnotes *[]*refAsFootnotes, currentTree *parse.Tr footnotesDefBlock = &ast.Node{Type: ast.NodeFootnotesDefBlock} var rendered []string + + var defIDs []string for _, foot := range *refFootnotes { - t, err := loadTreeWithCache(foot.defID, treeCache) + defIDs = append(defIDs, foot.defID) + } + defIDs = gulu.Str.RemoveDuplicatedElem(defIDs) + bts := treenode.GetBlockTrees(defIDs) + for _, foot := range *refFootnotes { + bt := bts[foot.defID] + if nil == bt { + logging.LogWarnf("not found block tree for footnote def [%s] refNum [%s]", foot.defID, foot.refNum) + continue + } + + t, err := loadTreeWithCache(bt.RootID, treeCache) if nil != err { logging.LogWarnf("load tree for footnote def [%s] refNum [%s] failed: %s", foot.defID, foot.refNum, err) continue @@ -3417,8 +3430,8 @@ func exportPandocConvertZip(baseFolderName string, docPaths, defBlockIDs []strin assetsOldNew, assetsNewOld := map[string]string{}, map[string]string{} luteEngine := util.NewLute() for i, p := range docPaths { - id := util.GetTreeID(p) - tree, md, isEmpty := exportMarkdownContent(id, ext, exportRefMode, defBlockIDs, false, treeCache) + rootID := util.GetTreeID(p) + tree, md, isEmpty := exportMarkdownContent(rootID, ext, exportRefMode, defBlockIDs, false, treeCache) if nil == tree { continue } @@ -3437,7 +3450,7 @@ func exportPandocConvertZip(baseFolderName string, docPaths, defBlockIDs []strin hash := fmt.Sprintf("%x", sha1.Sum([]byte(md))) if gulu.File.IsExist(writePath) && hash != wrotePathHash[writePath] { // 重名文档加 ID - p = hPath + "-" + id + ext + p = hPath + "-" + rootID + ext writePath = filepath.Join(exportFolder, p) } writeFolder := filepath.Dir(writePath) @@ -3743,13 +3756,15 @@ func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache *defBlockIDs = gulu.Str.RemoveDuplicatedElem(*defBlockIDs) } -func loadTreeWithCache(id string, treeCache map[string]*parse.Tree) (tree *parse.Tree, err error) { - if tree = treeCache[id]; nil != tree { +// loadTreeWithCache 加载树时优先从缓存获取,避免重复加载同一棵树 +// 注意传入的 rootID 必须是树的根节点 ID,不能是树中任意节点的 ID,否则会导致缓存失效和重复加载树 +func loadTreeWithCache(rootID string, treeCache map[string]*parse.Tree) (tree *parse.Tree, err error) { + if tree = treeCache[rootID]; nil != tree { return } - tree, err = LoadTreeByBlockID(id) + tree, err = LoadTreeByBlockID(rootID) if nil == err && nil != tree { - treeCache[id] = tree + treeCache[rootID] = tree } return }