Life period analysis based memory optimization method and system for go language program

CN122653628APending Publication Date: 2026-08-28UNIV OF SCI & TECH OF CHINA
View PDF 0 Cites 0 Cited by

Patent Information

Application Number
CN202611153117.2
Authority / Receiving Office
CN · China
Patent Type
Applications(China)
Current Assignee / Owner
Filing Date
2026-07-31
Publication Date
2026-08-28

AI Technical Summary

Technical Problem

但这类技术面临固有瓶颈:受限于Go快速编译的设计约束,指向分析只能采用流不敏感、域不敏感的保守策略,既无法区分对象及其字段在不同程序点的引用变化,也无法在合理开销下实现高精度上下文敏感分析,导致大量优化机会被遗漏

Benefits of technology

本发明通过采用由扩展逃逸状态分类、生命期等价图(LEG)、基于mhandler的代码转换组成的三层递进结构,解决了以下技术问题,并达到了相应的技术效果:

✦ Generated by Eureka AI based on patent content.

Smart Images

  • Figure CN122653628A_ABST
    Figure CN122653628A_ABST
Patent Text Reader

Abstract

The application relates to the technical field of computer program optimization, and discloses a Go language program memory optimization method and system based on life period analysis, which comprises the following steps: abstract syntax trees of Go source codes are traversed, extended escape analysis is performed, and an escape graph is constructed; a life period equivalence graph is constructed based on the escape graph; context-sensitive life period analysis is performed, life period end function of each object under corresponding calling context is determined by traversing a life period path; code conversion is performed based on an allocation handle, a memory management handle is created at the entrance of the life period end function, a release primitive is inserted before a return statement of the end function, and an object is registered to a management range of a corresponding handle at an object allocation point. Through light life period analysis, the application realizes compiler-assisted explicit recovery of a heap object without high-precision pointing analysis, effectively reduces recovery pressure, and improves runtime performance of a Go program.
Need to check novelty before this filing date? Find Prior Art

Description

Technical Field

[0001] This invention relates to the field of computer program optimization technology, specifically to a method and system for optimizing Go language programs based on lifecycle analysis. Background Technology

[0002] Go employs a memory management scheme that combines compile-time escape analysis with runtime concurrent garbage collection (GC). The compiler constructs an escape graph to determine whether an object has escaped to the heap, and escaped objects are reclaimed by the GC. However, native escape analysis only outputs a binary result of escape or not escape; once escape is determined, further tracing of the object's lifetime is abandoned. Furthermore, it takes a conservative approach to indirect assignment statements because it does not maintain a set of pointers, leading to many objects that could be allocated on the stack being mistakenly placed on the heap, increasing the GC burden.

[0003] To alleviate garbage collection (GC) pressure, compiler-assisted early garbage collection techniques have emerged in recent years. These methods introduce pointer analysis on top of escape analysis, identifying the last referenced point of an object and inserting explicit release primitives to achieve early heap object reclamation. However, these techniques face inherent bottlenecks: constrained by Go's fast compilation design, pointer analysis can only employ conservative strategies that are stream-insensitive and field-insensitive. This means it cannot distinguish changes in object and field references at different program points, nor can it achieve high-precision context-sensitive analysis with reasonable overhead, leading to the omission of numerous optimization opportunities. Furthermore, since optimization relies on indirectly inferring object lifetimes by tracing pointers, false positives and false negatives in pointer analysis severely limit optimization effectiveness. The insertion of explicit garbage collection code also faces engineering challenges related to compatibility with Go's type system and function signatures, further limiting the practicality and optimization benefits of existing solutions. Summary of the Invention

[0004] To address the aforementioned technical problems, this invention provides a Go language program memory optimization method and system based on lifecycle analysis. Its core concept lies in overcoming the binary limitation of traditional escape analysis, which only determines whether an object has escaped. By extending escape state classification and constructing a lifecycle equivalence graph, it achieves lightweight context-sensitive cross-process lifecycle analysis. Furthermore, it replaces the dependency on pointer analysis with a code transformation paradigm using allocation handles (mhandlers). This allows for the automatic identification of objects with statically determinable lifecycles in the heap and their explicit compiler-assisted reclamation without significantly increasing compilation overhead, effectively reducing the garbage collection (GC) pressure during Go program runtime.

[0005] To solve the above-mentioned technical problems, the present invention adopts the following technical solution: In a first aspect, the present invention provides a memory optimization method for Go language programs based on lifecycle analysis, comprising: The abstract syntax tree of the Go source code is traversed, an extended escape analysis is performed, the escape state of objects in the Go source code is expanded and classified into non-escape, escape within a function, escape to the caller and escape to the heap, and an escape graph is constructed to record the relationship between the object address flow. A lifetime equivalence graph is constructed based on the escape graph. The lifetime equivalence graph includes a set of entity nodes consisting of nodes in the escape state that have escaped to the caller and their associated nodes, a set of data flow edges obtained by removing intermediate nodes in the escape graph that do not belong to the set of entity nodes, and a set of cross-process edges obtained by mapping cross-function call relationships to cross-process edges. On the lifetime equivalence graph, context-sensitive lifetime analysis is performed on object nodes in the escape state that have escaped to the caller. By traversing the lifetime path, the lifetime endpoint function of each object in the corresponding calling context is determined. Code transformation is performed based on allocation handles. A memory management handle is created at the entry point of the lifetime-end function, a release primitive is inserted before the return statement of the lifetime-end function, and the object is registered to the management scope of the corresponding handle at the object allocation point.

[0006] In one embodiment, the expansion of the escape state classification of objects in the Go source code into non-escape, escape within a function, escape to the caller, and escape to the heap specifically includes: The "not escaped" means that the object has not escaped, and its lifetime is determined inside the allocation function, so stack allocation is performed directly. The term "escape within a function" refers to an object escaping due to excessive memory usage or the need for dynamic determination of memory usage, thus preventing allocation on the stack. However, the object's lifetime remains determined within the allocation function. The escape to the caller means that the object escapes because it is referenced by the callee. The object's address is returned through the return value or accessed by the callee through the formal parameter, and its lifetime extends into the caller function. The escape to the heap refers to an object escaping due to references to global variables or concurrent access by multiple threads, and the object's lifetime cannot be statically determined at compile time.

[0007] In one embodiment, the extended escape analysis further includes: Introducing a pointer set computation strategy, which only calculates the set pointed to by the destination pointer in the store statement in the Go source code, and the calculation scope is limited to inside the function; A two-stage processing approach is adopted. During the escape graph construction stage, only the destination pointer and the corresponding source node of the pointer set to be calculated in the storage statement are recorded. After the escape graph is fully constructed, the pointer set is solved iteratively, and the escape graph is updated according to the result of the pointer set integrity judgment.

[0008] In one embodiment, the set of entity nodes consisting of nodes in the escape state that have escaped to the caller and their associated nodes specifically includes: The set of entity nodes includes: The escape state is when a node escapes to the caller. ; The corresponding root cause node, i.e., the one that caused The escape state changes to escape to the caller's node; And the actual parameter node or return value receiver node corresponding to the root cause node at each calling point.

[0009] In one embodiment, the data flow edge set obtained by removing intermediate nodes that do not belong to the entity node set in the escape graph specifically includes: For two nodes m and n in the escape graph that belong to the set of entity nodes, if there exists a path from m to n in the escape graph, and none of the intermediate nodes on the path belong to the set of entity nodes, then the path is compressed into an edge from m to n, and the weight of the edge is the sum of the weights of all edges on the original path.

[0010] In one embodiment, the set of cross-process edges obtained by mapping cross-function call relationships to cross-process edges specifically includes: The cross-process edges of the lifetime equivalence graph are used to connect the data streams of different functions. For each function called at each call point, a cross-process edge is added from the formal parameter to the actual parameter corresponding to the formal parameter at the call point, and a cross-process edge is added from the return value to the return value receiver corresponding to the return value at the call point, for each formal parameter and return value in the function's summary. The weight of the edge is the identifier of the call point.

[0011] In one embodiment, the step of performing context-sensitive lifetime analysis on object nodes in the escape state (escape to the caller) on the lifetime equivalence graph specifically includes: The working list method is used to perform a depth-first traversal of all object nodes in the escape state that have escaped to the caller: For each object, the object's node is added to the working queue as the starting node; each time a node is taken out of the working queue, it is checked whether there is a successor node that can continue to hold the object's reference. If not, the path from the object's node to the taken-out node is recorded as a lifetime path. If it exists, the successor node is added to the queue to continue exploration; the shortest path length of each node is maintained during the traversal.

[0012] In one embodiment, determining the lifecycle termination function for each object in its corresponding calling context by traversing the lifecycle path specifically includes: The lifetime path is a path that starts from an object node, travels along the edges of the lifetime equivalence graph to a pointer node, and satisfies the following conditions: The pointer node is neither a formal parameter or return value node nor a heap node; The pointer node directly or indirectly holds a reference to the object; The pointer node is the last node that holds an object reference that can be reached along the current path; The sequence of cross-process edges in the path uniquely determines the calling context.

[0013] In one embodiment, the allocation handle includes: The `define_handler` primitive is used to create a handle at the function entry point; The `free` primitive is used to release all objects managed by a handle before a function returns. The recv_handler primitive is used to obtain a handle provided by the caller pointing to the location of a specified parameter or return value. The send_handler primitive is used to forward the handle to the callee at the calling point; The clr_handler primitive is used to clear the handles that have been sent. The code conversion based on the allocated handle specifically includes: The allocated handle is passed from the caller to the callee along the lifetime path through a handle passing mechanism. Before the call, the handle provided by the caller is obtained through the recv_handler primitive. During the call, the handle is forwarded to the callee through the send_handler primitive. After the call, the sent handle is cleared through the clr_handler primitive, so that the code transformation is consistent with the context-sensitive lifetime analysis results.

[0014] Secondly, the present invention provides a Go language program memory optimization system based on lifecycle analysis, for implementing the method of any embodiment of the first aspect, including: The escape analysis module traverses the abstract syntax tree of the Go source code, performs extended escape analysis, and classifies the escape state of objects in the Go source code into non-escape, escape within a function, escape to the caller, and escape to the heap, and constructs an escape graph that records the relationship between object address flow. The lifetime equivalence graph construction module constructs a lifetime equivalence graph based on the escape graph. The lifetime equivalence graph includes the entity node set consisting of nodes in the escape state that have escaped to the caller and their associated nodes, the data flow edge set obtained by removing intermediate nodes in the escape graph that do not belong to the entity node set, and the cross-process edge set obtained by mapping cross-function call relationships to cross-process edges. The lifetime analysis module performs context-sensitive lifetime analysis on object nodes in the escape state that have escaped to the caller on the lifetime equivalence graph. It determines the lifetime endpoint function of each object in the corresponding calling context by traversing the lifetime path. The code transformation module performs code transformation based on the allocation handle. It creates a memory management handle at the entry point of the lifetime-end function, inserts a release primitive before the return statement of the lifetime-end function, and registers the object to the management scope of the corresponding handle at the object allocation point.

[0015] The system and method in this invention correspond to each other; the specific technical solutions applicable to the method are also applicable to the system.

[0016] Compared with the prior art, the beneficial technical effects of the present invention are: This invention solves the following technical problems and achieves the corresponding technical effects by employing a three-layer progressive structure consisting of extended escape state classification, lifetime equivalence graph (LEG), and mhandler-based code transformation: (1) This solves the problem that traditional escape analysis only uses a binary judgment to determine whether an object has escaped and abandons further analysis of objects that have escaped from the heap. By subdividing the escape state into NoEscape (not escaped), EscapeWithinFunc (escaped within a function), EscapeToCaller (escaped to the caller), and EscapeHeap (escaped to the heap), and recording the root cause node, escape analysis can identify how an object escapes, providing an accurate state basis for subsequent lifetime analysis.

[0017] (2) It solves the dilemma of the trade-off between accuracy and compilation speed faced by existing methods (such as GoFree) due to their reliance on high-precision pointer analysis. By replacing pointer-based optimization with object-based optimization and high-precision pointer analysis with reachability analysis based on lifetime equivalence graphs, context-sensitive lifetime identification is achieved while maintaining compilation speed, thus overcoming the optimization omissions caused by the flow / domain insensitive pointer analysis in existing technologies.

[0018] (3) It solves the technical challenge of safely garbage collecting objects without knowing the specific reference pointer. By using a code transformation paradigm based on allocation handles, it tracks the end of the object's lifetime at the function level and replaces direct pointer operations with allocation handles, bypassing the dependence on precise pointer analysis. Handle passing is implemented based on the goroutine native stack (GLS), which does not require modification of the function signature and ensures full compatibility with Go's existing GC mechanism and interface type system.

[0019] In benchmark tests of real open-source Go projects, this invention optimized heap allocation points by approximately 7.91%; reclaimed up to 11% of memory at runtime; reduced GC triggers by 13%; and shortened application execution time by an average of 1.26%. Attached Figure Description

[0020] Figure 1 This is a flowchart of the method of the present invention; Figure 2 This is a diagram of the overall architecture of the present invention. Detailed Implementation

[0021] A preferred embodiment of the present invention will now be described in detail with reference to the accompanying drawings.

[0022] like Figure 1 As shown, a Go language program memory optimization method based on lifecycle analysis in this invention includes the following steps: S1 traverses the abstract syntax tree of the Go source code, performs extended escape analysis, expands the classification of the escape state of objects in the Go source code into non-escape, escape within a function, escape to the caller, and escape to the heap, and constructs an escape graph that records the relationship between the object address flow. S2, construct a lifetime equivalence graph based on the escape graph. The lifetime equivalence graph includes a set of entity nodes consisting of nodes in the escape state that have escaped to the caller and associated nodes, a set of data flow edges obtained by removing intermediate nodes in the escape graph that do not belong to the set of entity nodes, and a set of cross-process edges obtained by mapping cross-function call relationships to cross-process edges. S3 performs context-sensitive lifetime analysis on object nodes in the lifetime equivalence graph that are in the escape state and have escaped to the caller. It determines the lifetime endpoint function of each object in the corresponding calling context by traversing the lifetime path. S4 performs code transformation based on the allocation handle, creates a memory management handle at the entry point of the lifetime termination function, inserts a release primitive before the return statement of the termination function, and registers the object to the management scope of the corresponding handle at the object allocation point.

[0023] Figure 2 The overall architecture of the invention is shown. For example... Figure 2As shown, the architecture mainly includes a native escape analysis section and an extended escape analysis section as described in this invention. In the batch-level analysis, the native escape analysis section provides basic data flow information for subsequent extended escape analysis by performing escape graph construction, escape state calculation, and post-processing. The extended escape analysis section, based on the native escape analysis, further performs extended inter-process analysis, pointer set calculation, extended escape state calculation, and lifetime equivalence graph construction. After the batch-level analysis is completed, the extended escape analysis section also performs lifetime analysis at the compiler unit level. In addition, it includes a runtime support layer; the runtime support layer performs heap / stack allocation decisions, region memory management, and explicit memory reclamation operations based on the analysis results of the extended escape analysis section. The call graph is used to describe the function call relationships in the program, and the batch-level analysis proceeds from bottom to top according to the call graph.

[0024] The present invention will be described in detail below in several parts.

[0025] 1. Extensions to escape analysis, including extended classification of escape states and computation of pointer sets.

[0026] Using the Abstract Syntax Tree (AST) corresponding to the Go source code as input, this invention traverses the AST, performs extended escape analysis, and constructs an escape graph. The escape graph records the flow of object addresses between variables and expressions in the program. Compared to traditional Go escape analysis, this invention enhances the process in two aspects.

[0027] (1) Extended classification of escape states: Traditional escape analysis simply categorizes objects as either escaped or not, failing to differentiate between objects with different lifecycle characteristics. This invention, based on the fundamental reasons for object escape, expands the escape state into four categories, forming an escape state lattice: NoEscape (not escaped). EscapeWithinFunc (Escape within function) EscapeToCaller (Escape to Caller) EscapeHeap Indicates a partial order.

[0028] The specific definitions are as follows: NoEscape: The object has not escaped, its lifetime is determined within the allocation function, and stack allocation can be performed directly.

[0029] EscapeWithinFunc: An object escapes due to excessive memory usage or the amount of memory usage needs to be dynamically determined. It cannot be allocated on the stack, but its lifetime is still determined inside the allocation function. It can be safely reclaimed after the function returns.

[0030] EscapeToCaller: The object escapes due to the callee's reference. Its address is returned via the return value or accessed by the callee via the formal parameter. Its lifetime may extend into the caller function, requiring further cross-function analysis to determine the end of its lifetime.

[0031] EscapeHeap: An object escapes due to reference to a global variable or concurrent access by multiple threads. Its lifetime cannot be statically determined at compile time and is managed by runtime garbage collection (GC).

[0032] The initial values ​​of the escape state are set according to the object's allocation characteristics: objects without escape characteristics are initialized to NoEscape; objects with excessive memory usage or whose memory usage needs to be dynamically determined are initialized to EscapeWithinFunc; objects referenced by formal parameters or returned via return values ​​are initialized to EscapeToCaller; and objects referenced by global variables or accessed concurrently are initialized to EscapeHeap. Based on this, by traversing and analyzing the constraints of the escape state in the escape graph, if the address of object o flows to pointer p, denoted as... If the escape state ES(p) of p is higher than the escape state ES(o) of o, then update ES(o) = ES(p), and finally iterate until a fixed point is reached. At the same time, maintain the mapping function attrN to record the root cause node that causes the escape state of each node to change, providing key clues for the construction of the lifetime equivalence graph.

[0033] (2) Precise modeling of stored statements and calculation of the pointed set: Go's native escape analysis does not attempt to compute the set of pointers, resulting in... Storage statements in the form of "" can only be handled conservatively: because the specific memory location pointed to by p cannot be determined, the analysis assumes that the value of q may flow to any location (including the heap). This causes a large number of objects that could have been accurately analyzed to be incorrectly identified as escapes.

[0034] This invention introduces an on-demand, in-process, lightweight pointer set computation strategy to solve this problem. The core idea of ​​this strategy is to compute the pointer set only for the target pointer in the stored statement, and to limit the computation scope to the function, thus avoiding the introduction of high overhead for full-program analysis.

[0035] To achieve this goal, we first utilize the data flow information already recorded in the escape graph to define a method for calculating the pointer's pointed-to set: if there exists a path from object o to pointer p in the escape graph that satisfies the condition that there exists a path from o to p with a weighted length of -1, and the first edge on the path is an address-taking edge with a weight of -1, then o is considered to belong to the pointed-to set of p. We use points-to(p) to represent the pointed-to set of p, i.e. .

[0036] However, this calculation method is not effective in all cases. Escape graphs only record data flow within a function; for global variables and parameters that may be modified outside the function, their pointer sets may be incomplete. Therefore, we define a rule for determining the integrity of pointer sets: If p is a global variable or a formal parameter, then the set it points to is incomplete; If p is copied from q by assignment, and the set that q points to is incomplete, then the set that p points to is also incomplete.

[0037] Because Go's escape analysis is based on sequential traversal of the abstract syntax tree and does not follow the data flow order, the set of pointers cannot be correctly calculated before the escape graph is fully constructed. Therefore, a two-stage processing approach is adopted: During the escape graph construction phase, only the destination pointer to the set and its source node that need to be calculated in the stored statement are recorded, and they are not solved immediately. After the escape graph is fully constructed, the set of pointers is solved iteratively, and the escape graph is updated: for each complete storage statement where the destination pointer points to the set... ", for each Add an edge from q to o (with a weight of 0); for points to incomplete sets, add an edge from q to a heap node as a conservative approach.

[0038] 2. Construct a lifecycle equivalence graph (LEG).

[0039] Based on escape analysis, a lifetime equivalence graph (LEG) is constructed. A lifetime equivalence graph is a programmatic abstraction used to trace object reference relationships across processes. The construction of the lifetime equivalence graph consists of the following three sub-steps.

[0040] (1) Identification of entity node sets: The set of entity nodes L' in the lifecycle equivalence graph contains the following three types of nodes: : All nodes in the escape state of EscapeToCaller. The objects represented by these nodes are the main targets of the lifetime analysis in this invention. Their reference relationships may propagate across functions, requiring further tracking of their lifetimes.

[0041] The escape states mentioned above are the root cause nodes corresponding to the EscapeToCaller nodes, that is, the nodes that caused their escape states to change to EscapeToCaller. Based on the properties of root cause nodes, they all correspond to function parameter or return value nodes.

[0042] : This section lists the corresponding actual parameter or return value receiver nodes for each formal parameter or return value node at each call point. For example, if function f is called at call point cs, where the formal parameter x of f corresponds to the actual parameter a, and the return value r0 of f corresponds to the receiver v, then the nodes corresponding to a and v are included in the list. .

[0043] In addition, the lifetime equivalence graph always contains a special heap node to represent references to the external environment that cannot be statically analyzed.

[0044] (2) Extraction of path compression subgraph: For each compilation unit, the escape graph EG=(L,E) is used to extract a path compression subgraph based on the entity node set L', forming a data flow edge set of the lifecycle equivalence graph. The specific rule is as follows: For two nodes m and n in the escape graph that both belong to the lifespan equivalence graph entity node set, if there exists a path from m to n in the escape graph, and all intermediate nodes on the path do not belong to the lifespan equivalence graph, then the path is compressed into an edge from m to n in the lifespan equivalence graph, with the weight being the sum of the weights of all edges on the original path. Path compression is implemented through a ByPass operation: if an edge exists in the escape graph... and Then add a line The edges are removed and the original edges are deleted. This process is repeated until all non-lifetime equivalence intermediate nodes are removed. This operation significantly reduces the size of the graph while maintaining the semantics of the data flow.

[0045] (3) Adding cross-process edges: Set of cross-process edges in a lifetime equivalence graph Used to connect data streams of different functions. For each function f called at call point cs, for each formal parameter x and return value r in the summary of f, add a cross-procedural edge from x to the actual parameter of x at call point cs (or from r to the return value receiver of r at cs). The weight of the edge is the call point identifier cs to distinguish different call contexts.

[0046] To achieve cross-process reference propagation, this invention introduces two mechanisms: reference tags and virtual nodes. For a formal parameter or return value x, its reference tag rtag_x = (d, refDepth), d ≥ 0, refDepth ≥ 1, indicating that after dereferencing x d times, the object allocated by the caller at the refDepth level (the escape state of these objects is EscapeToCaller) can be reached. Here, d is the dereferencing depth, and refDepth is the number of levels of reference relationships between caller function objects. For example, if the reference tag of the formal parameter p is (1, 2), it indicates... The object o0 references another object o1, meaning p indirectly accesses two callee-allocated objects. When analyzing the call point, a virtual node chain is created in the caller escape graph to instantiate these referenced objects, enabling cross-function references to propagate and be analyzed within a unified escape graph framework.

[0047] 3. Context-sensitive lifetime analysis based on lifetime equivalence graphs.

[0048] Perform context-sensitive lifetime analysis on all object nodes in the lifetime equivalence graph that are in the state of EscapeToCaller. Lifetime is function-granular: the lifetime of object o in its corresponding calling context can be represented as... In this context, ctxt is uniquely determined by the call point sequence, and the endpoint function... For the function that was last accessed by the object in this context, Objects can be safely reclaimed upon exit.

[0049] (1) Definition of life-cycle pathway: In a lifetime equivalence graph, if a pointer node p is reached from an object node o along an edge of the lifetime equivalence graph, and the following conditions are met, then the path is defined as a lifetime path of object o: p is not a heap node, and p is not a parameter or return value node of any function (i.e., (Not true). If p is a heap node, it means the object has been propagated to the program's global space, and its lifetime cannot be statically determined; if p is a parameter or return value node, it means the reference may propagate further outside the current compilation unit, and this path is an incomplete path.

[0050] p directly or indirectly references object o, meaning the address of o ultimately points to p through an edge in the lifetime equivalence graph. A directed path.

[0051] There is no successor node q. q has acquired the value of p and can continue to pass references to o through q. That is, p is the last node that holds a reference to o that can be reached along the current path.

[0052] The sequence of cross-process edges in each lifetime path uniquely determines the calling context ctxt. For example, for a lifetime path... ( and Let's consider two cross-process edges. Function `bar` calls function `foo` at call point C1, and function `zoo` calls function `bar` at call point C0. Let `r0_foo` represent the first return value of `foo`, and `r0_bar` represent the first return value of function `bar`. This lifetime path represents object `o` being created from `foo`, passed through call point C1 to `p` in `bar`, then through call point C0 to `a` in `zoo`, reaching its lifetime end when `zoo` exits.

[0053] (2) Life-cycle analysis: Using a worklist approach similar to Bellman-Ford's, for all The objects in the algorithm are traversed one by one using a depth-first search. For each object o, its node is added to the working queue as the starting node. Each time, a node p is taken from the queue, and it is checked whether p has a successor node that can continue to hold a reference to o. If not, the path from o to p is recorded as a lifetime path; if it exists, the successor node is added to the queue to continue exploration. During the traversal, the shortest path length of each node is maintained to avoid loops that prevent the algorithm from exiting. Paths ending at parameter or return value nodes are marked as incomplete paths and discarded from the final result. Table 1 describes the main flow of the algorithm.

[0054] Table 1, Lifetime Analysis Algorithm:

[0055] Table 1 shows the algorithm for lifetime analysis, which takes a lifetime equivalence graph LEG(L', E') as input and outputs a set of lifetime paths LTs for all paths. The third row begins with... The process iterates from each node in the list. This traversal is implemented using a working list algorithm. The working list is represented using a queue structure, initialized in line 4. Line 5 begins iterating through the working list until it is empty. Line 6 retrieves the first element from the list and assigns it to `l`. Line 7 initializes `P` to represent the path currently traversed. Line 8 sets a variable `LTEnd` to indicate whether the current path `P` is a complete lifetime path (true if it is, false otherwise). Lines 9-14 iterate through the adjacent nodes of the current node `l`. If an adjacent node uses `l` or its value is assigned to `l`, it adds that adjacent node to the working list and sets `LTEnd` to false. Line 16 determines whether `P` is a lifetime path based on its definition; if so, it records the call context of `P` in `LTs`.

[0056] 4. Code transformation and memory optimization based on allocation handle (mhandler).

[0057] Based on each valid lifetime path obtained from the analysis, the Go source code undergoes compiler-assisted code transformation to achieve early memory reclamation of objects. Since the lifetime analysis in this invention only identifies the object's endpoint function and does not track the specific pointers referencing the object within that function, a reclamation mechanism that does not rely on specific pointer operations is needed. Therefore, this invention designs a novel code transformation paradigm based on allocation handles (mhandler), which consists of three parts.

[0058] (1) Definition of handle and handle-based recycling: For the endpoint function on the lifetime path The `define_handler` primitive is inserted at the function entry point to create a memory management handle (`mhandler`) for the function; the `free` primitive is inserted before each `return` statement of the function to release all objects currently managed by the `mhandler`. This "definition-use-release" pattern ensures that the lifetime of an object is strictly consistent with the execution scope of the final function.

[0059] (2) Context-dependent handle passing: Because lifetime analysis is context-sensitive, optimized code transformations must also be performed within the correct calling context. Therefore, a handle-passing mechanism is used to pass the allocation handle along the lifetime path from the caller to the callee: Before the call (recv_handler): Use recv_handler(idx) to obtain a handle provided by the caller pointing to the position of the idx-th parameter or return value.

[0060] At call (send_handler): use send_handler(idx) to forward the handle to the callee at the corresponding call point. The idx parameter in the primitive is used to distinguish different handles passed through different parameter or return value positions at the same call point.

[0061] After the call (clr_handler): Use clr_handler() to clear all sent handles, preventing handles from being accidentally consumed by other call points within the same function, and ensuring context accuracy.

[0062] (3) Handle-based allocation: At the object allocation point, `recv_handler` is used to retrieve the `mhandler` passed down along the context path, and then the `alloc_opt(mhandler)` primitive is used to allocate the object under that handle. The object is automatically registered into the management scope of this `mhandler`, and is uniformly reclaimed by the `free` primitive when the terminal function exits. In this way, object allocation and reclamation are uniformly incorporated into the handle management chain, completing fully automatic memory optimization guided by lifetime.

[0063] The terminology used herein is for the purpose of describing particular embodiments only and is not intended to limit the invention. The terms “comprising,” “including,” etc., as used herein indicate the presence of the stated features, steps, operations, and / or components, but do not exclude the presence or addition of one or more other features, steps, operations, or components.

[0064] It should be understood that although the steps in the flowcharts of the accompanying drawings are shown sequentially as indicated by the arrows, these steps are not necessarily executed in the order indicated by the arrows. Unless explicitly stated herein, there is no strict order restriction on the execution of these steps, and they can be executed in other orders. Moreover, at least some of the steps in the flowcharts of the accompanying drawings may include multiple steps or stages, which are not necessarily completed at the same time, but may be executed at different times, and the execution order of these steps or stages is not necessarily sequential, but may be performed alternately or in turn with other steps or at least some of the steps or stages of other steps.

[0065] Based on the description of the above method embodiments, the present invention also provides a system. The system may be a system that uses software (applications), modules, components, servers, clients, etc., using the methods described in the embodiments of this specification, combined with necessary implementation hardware. Since the implementation schemes and methods for solving the problem are similar, the specific system implementations in the embodiments of this specification can be found in the implementations of the foregoing methods, and repeated details will not be described again. Although the system is preferably implemented in software, hardware implementation, or a combination of software and hardware, is also possible and contemplated.

[0066] The technical features of the above embodiments can be combined in any way. For the sake of brevity, not all possible combinations of the technical features in the above embodiments are described. However, as long as there is no contradiction in the combination of these technical features, they should be considered to be within the scope of this specification.

[0067] It will be apparent to those skilled in the art that the present invention is not limited to the details of the exemplary embodiments described above, and that the invention can be implemented in other specific forms without departing from its spirit or essential characteristics. Therefore, the embodiments should be considered in all respects as exemplary and non-limiting, and the scope of the invention is defined by the appended claims rather than the foregoing description. Thus, all variations falling within the meaning and scope of equivalents of the claims are intended to be included within the present invention, and no reference numerals in the claims should be construed as limiting the scope of the claims.

[0068] Furthermore, it should be understood that although this specification describes embodiments, not every embodiment contains only one independent technical solution. This narrative style is merely for clarity. Those skilled in the art should consider the specification as a whole, and the technical solutions in each embodiment can also be appropriately combined to form other embodiments that can be understood by those skilled in the art.

Claims

1. A memory optimization method for Go language programs based on lifecycle analysis, characterized in that, include: The abstract syntax tree of the Go source code is traversed, an extended escape analysis is performed, the escape state of objects in the Go source code is expanded and classified into non-escape, escape within a function, escape to the caller and escape to the heap, and an escape graph is constructed to record the relationship between the object address flow. A lifetime equivalence graph is constructed based on the escape graph. The lifetime equivalence graph includes a set of entity nodes consisting of nodes in the escape state that have escaped to the caller and their associated nodes, a set of data flow edges obtained by removing intermediate nodes in the escape graph that do not belong to the set of entity nodes, and a set of cross-process edges obtained by mapping cross-function call relationships to cross-process edges. On the lifetime equivalence graph, context-sensitive lifetime analysis is performed on object nodes in the escape state that have escaped to the caller. By traversing the lifetime path, the lifetime endpoint function of each object in the corresponding calling context is determined. Code transformation is performed based on allocation handles. A memory management handle is created at the entry point of the lifetime-end function, a release primitive is inserted before the return statement of the lifetime-end function, and the object is registered to the management scope of the corresponding handle at the object allocation point.

2. The Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The expansion of the escape state classification for objects in Go source code into non-escape, escape within a function, escape to the caller, and escape to the heap specifically includes: The "not escaped" means that the object has not escaped, and its lifetime is determined inside the allocation function, so stack allocation is performed directly. The term "escape within a function" refers to an object escaping due to excessive memory usage or the need for dynamic determination of memory usage, thus preventing allocation on the stack. However, the object's lifetime remains determined within the allocation function. The escape to the caller means that the object escapes because it is referenced by the callee. The object's address is returned through the return value or accessed by the callee through the formal parameter, and its lifetime extends into the caller function. The escape to the heap refers to an object escaping due to references to global variables or concurrent access by multiple threads, and the object's lifetime cannot be statically determined at compile time.

3. The Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The escape analysis for the execution extension also includes: Introducing a pointer set computation strategy, which only calculates the set pointed to by the destination pointer in the store statement in the Go source code, and the calculation scope is limited to inside the function; A two-stage processing approach is adopted. During the escape graph construction stage, only the destination pointer and the corresponding source node of the pointer set to be calculated in the storage statement are recorded. After the escape graph is fully constructed, the pointer set is solved iteratively, and the escape graph is updated according to the result of the pointer set integrity judgment.

4. The Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The set of entity nodes consisting of nodes in the escape state that have escaped to the caller and their associated nodes specifically includes: The set of entity nodes includes: The escape state is when a node escapes to the caller. ; The corresponding root cause node, i.e., the one that caused The escape state changes to escape to the caller's node; And the actual parameter node or return value receiver node corresponding to the root cause node at each calling point.

5. The Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The data flow edge set obtained by removing intermediate nodes that do not belong to the entity node set in the escape graph specifically includes: For two nodes m and n in the escape graph that belong to the set of entity nodes, if there exists a path from m to n in the escape graph, and none of the intermediate nodes on the path belong to the set of entity nodes, then the path is compressed into an edge from m to n, and the weight of the edge is the sum of the weights of all edges on the original path.

6. The Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The set of cross-process edges obtained by mapping cross-function call relationships to cross-process edges specifically includes: The cross-process edges of the lifetime equivalence graph are used to connect the data streams of different functions. For each function called at each call point, a cross-process edge is added from the formal parameter to the actual parameter corresponding to the formal parameter at the call point, and a cross-process edge is added from the return value to the return value receiver corresponding to the return value at the call point, for each formal parameter and return value in the function's summary. The weight of the edge is the identifier of the call point.

7. The Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The context-sensitive lifetime analysis of object nodes in the escape state that have escaped to the caller on the lifetime equivalence graph specifically includes: The working list method is used to perform a depth-first traversal of all object nodes in the escape state that have escaped to the caller: For each object, the object's node is added to the working queue as the starting node; each time a node is taken out of the working queue, it is checked whether there is a successor node that can continue to hold the object's reference. If not, the path from the object's node to the taken-out node is recorded as a lifetime path. If it exists, the successor node is added to the queue to continue exploration; the shortest path length of each node is maintained during the traversal.

8. A Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The method of determining the lifecycle endpoint function of each object in its corresponding calling context by traversing the lifecycle path specifically includes: The lifetime path is a path that starts from an object node, travels along the edges of the lifetime equivalence graph to a pointer node, and satisfies the following conditions: The pointer node is neither a formal parameter or return value node nor a heap node; The pointer node directly or indirectly holds a reference to the object; The pointer node is the last node that holds an object reference that can be reached along the current path; The sequence of cross-process edges in the path uniquely determines the calling context.

9. A Go language program memory optimization method based on lifecycle analysis according to claim 1, characterized in that, The allocation handle includes: The `define_handler` primitive is used to create a handle at the function entry point; The `free` primitive is used to release all objects managed by a handle before a function returns. The recv_handler primitive is used to obtain a handle provided by the caller pointing to the location of a specified parameter or return value. The send_handler primitive is used to forward the handle to the callee at the calling point; The clr_handler primitive is used to clear the handles that have been sent. The code conversion based on the allocated handle specifically includes: The allocated handle is passed from the caller to the callee along the lifetime path through a handle passing mechanism. Before the call, the handle provided by the caller is obtained through the recv_handler primitive. During the call, the handle is forwarded to the callee through the send_handler primitive. After the call, the sent handle is cleared through the clr_handler primitive, so that the code transformation is consistent with the context-sensitive lifetime analysis results.

10. A Go language program memory optimization system based on lifecycle analysis, used to implement the method of any one of claims 1 to 9, characterized in that, include: The escape analysis module traverses the abstract syntax tree of the Go source code, performs extended escape analysis, and classifies the escape state of objects in the Go source code into non-escape, escape within a function, escape to the caller, and escape to the heap, and constructs an escape graph that records the relationship between object address flow. The lifetime equivalence graph construction module constructs a lifetime equivalence graph based on the escape graph. The lifetime equivalence graph includes the entity node set consisting of nodes in the escape state that have escaped to the caller and their associated nodes, the data flow edge set obtained by removing intermediate nodes in the escape graph that do not belong to the entity node set, and the cross-process edge set obtained by mapping cross-function call relationships to cross-process edges. The lifetime analysis module performs context-sensitive lifetime analysis on object nodes in the escape state that have escaped to the caller on the lifetime equivalence graph. It determines the lifetime endpoint function of each object in the corresponding calling context by traversing the lifetime path. The code transformation module performs code transformation based on the allocation handle. It creates a memory management handle at the entry point of the lifetime-end function, inserts a release primitive before the return statement of the lifetime-end function, and registers the object to the management scope of the corresponding handle at the object allocation point.