Page 244 - 《软件学报》2026年第3期
P. 244

李清伟 等: Go  语言程序的内存性能与安全问题实证研究                                                   1207


                 动态内存分配分析与优化提出挑战, 而            call 模式则针对跨函数的过程间动态内存分配分析与优化提出挑战. 另外
                 ret 模式也存在一定的比例, 揭示了过程间动态内存分配优化的潜力.

                                         表 5 转换为接口的模式分布以及被转换类型分布

                       形式           类别        数量       比例 (%)    接口类型 (%)     非指针类型 (%)      指针类型 (%)
                    LHS = RHS      assign    920 949    20.16       71.69         23.65         4.66
                     o.m(a1, a2)    call     3 540 073  77.48       45.51         37.24         17.26
                   (interface{})(src)  conversion  4 751  0.10      5.20          64.11         30.69
                      return a       ret     100 806     2.21       6.56          56.04         37.08
                      ch <- a       send      2 218      0.05       9.20          81.61         9.20
                            总计               4 568 797  100.00      49.92         34.96         15.11

                    进一步分析被转换为接口类型的数据类型的分布, 本文将这些类型分为                        3  类: 接口类型、非指针类型和指针
                 类型. 接口类型和指针类型在转化为接口类型时不需要动态分配新对象. 非指针类型转换为接口类型需要动态分
                 配新的转换前类型对象. 3       种类型对象被转换为接口类型的分布如表               5  所示. 在  assign  和  call 模式中, 接口类型的
                 转换频率较高, 在     conversion、ret 和  send  模式中, 非指针类型占据主导, 这导致了显著的隐式堆内存分配需求. 因
                 此, 在进行内存优化时, 应优先关注非指针类型转换的分配问题, 以减少隐式分配带来的性能开销.
                    结论   2. 在接口类型转换的模式中, assign      模式和   call 模式两类模式占据绝大部分, 表明分析接口相关的内
                 存分配时应重点关注这两类模式. 此外, 由于非指针类型转换为接口类型需要在堆上新分配对象, 在涉及优化
                 conversion、ret、send  模式时需要特别注意这些隐式的堆内存分配. 由于            assign  和 call 模式基数较大, 其中非指针
                 类型转换为接口类型引发的隐式堆分配也是值得内存优化关注的点.
                  4   RQ2: 内存安全问题模式

                    围绕开源    Go  语言项目中的内存安全问题, 本节首先确定研究内存安全问题的关键词, 然后统计通过不同关
                 键词搜索得到的      Issues 数量分布, 以回答   RQ2  中的内存安全问题存在性和分布问题, 并分析出现较多内存安全问
                 题的仓库的领域分布, 以揭示         RQ2  中仓库领域与内存安全问题之间的关系. 最后本节总结与                 3  个关键词相关的内
                 存安全问题的模式.
                  4.1   内存安全相关问题筛选
                    本文从   CVE [34] 、CWE [35] 和  Go  官方维护的漏洞数据库  [36] 搜索内存安全问题. 其中, 只有    CWE 提供了对内存
                 安全问题的分类总结, 包含了         C、C++、Java、PHP   等语言中的常见内存安全问题以及不同年份的                 Top N  安全问
                 题视图  [37] . 由于  CWE  中未涵盖  Go 语言特定内存问题的视图, 本文基于       CWE  的两个视图——CWE Top 25 (2022)   [38]
                 和  Software Written in C++ [39] , 筛除非内存安全问题和在  Go  语言中不太可能出现的问题, 结合       Go  语言在运行时
                 检查中常见的报错信息        [40] , 筛选出以下  3  个关键词, 分别为“memory leak”“invalid memory address OR nil pointer”
                 “dangling pointer”. 其中, “memory leak” 是指内存泄漏问题, 归属于  LEAK; “invalid memory address OR nil pointer”
                 通常在应用程序执行时由         Go  运行时检测到空指针解引用时报错, 归属于             NPD. “dangling pointer”则是指资源对象
                 (如内存对象或文件描述符对象) 被释放之后, 内存中还包含对这些已释放资源的引用, 归属于                            DP. 基于这  3  个关
                 键词, 本文使用图     4  所展示的方法, 搜索了     996  个  Go  语言仓库过去  5  年内更新的  Issues/PRs 以及包含  memory  关
                 键词的   Issues/PRs, 后者可视为内存安全问题的总集. 基于这些           Issues/PRs, 对含内存安全问题的仓库的领域特点
                 进行分析, 借此进一步探索内存安全问题在不同领域的发生情况.
                  4.2   内存安全问题分布
                    本节将基于内存安全相关的          Issues/PRs 的数量, 分析内存安全问题在实际        Go  应用中的分布情况.
                  4.2.1    内存安全问题数量分布
                    根据图   4, 针对从  GitHub  中获取的  996  个最近  1  年内更新的仓库, 通过设置      3  类关键词进行搜索, 得到了不
   239   240   241   242   243   244   245   246   247   248   249