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

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



                    20
                                                                                    300
                                                                         LEAK            LEAK
                    18
                                                                         NPD             NPD       251
                    16                                                              250
                    14
                                                                                    200
                    12
                   频数  10                                                          变更行数  150
                     8                                                                     111
                                                                                    100
                     6
                                                                                          60
                     4                                                               50           48
                     2
                                                                                     0
                     0
                       −10 0  10 20 30 40 50 60 70 80 90 100  110  120  130  140  150  160  170  180  190  LEAK  NPD
                                             修复时间间隔 (天)                                  内存安全问题类别
                                      图 5    修复时间间隔直方图                            图 6    代码变更行数箱型图
                  5   RQ3: 内存问题的自动检测

                    针对第   4  节总结的一系列内存问题模式, 如何自动检测它们仍然面临挑战. 本节给出一些可能的自动检测方
                 案以尝试解决这个问题.
                  5.1   一些问题模式的自动检测方法可能性
                    要实现自动检测, 问题模式必须足够简单, 能够通过基础的过程内数据流分析算法进行检测. 然而对于跨多个
                 函数的问题, 即使能够实现自动检测, 也会由于分析时间过长或者误报过多导致实用性较低. 此外, 当开发者在应
                 用中自定义了内存分配与回收算法时, 检测方法需要专门为该应用设计, 难以广泛适用于其他                             Go  项目.
                    对于  L1 模式来说, 自动检测首先需要识别资源类型. 这需要通过人工标注或者其他自动的方式实现资源类型
                 的标注. 假定定义了      Open、Close 方法的结构体类型为资源类型. 对于           L1-1  模式, 可以检测资源类型定义中是否
                 引用了其他资源类型, 如果引用, 进一步检查            Close 方法中是否调用了其他资源的          Close 方法判断代码是否存在问
                 题. 阻碍该问题自动化检测的难点在于, 不同资源类型的申请和释放函数可能有不同的函数名称和签名, 需要通过
                 标注识别, 并且需要识别不同结构体之间的引用关系. 对于                  L1-2  模式, 可以通过使用描述资源打开或者关闭状态
                 的状态机以及前向分析判断被打开的资源是否在程序结束时一定被关闭.闭.
                    对于  L2-1、L2-2  模式, 这些模式涉及较多的分支语句, 可能需要引入路径敏感性, 为资源对象添加条件属性,
                 匹配特定条件下资源释放的执行情况. 对于              L2-3  模式, 本文使用  QLStat 进行了检测, 将在后文中详细描述该方法.
                    对于  L3-1  模式, 需要分析在不同协程中, 是否存在特定的数据结构是可以被共享的. 阻碍该模式自动化检测
                 的难点在于, 首先需要识别在不同协程之间共享的类型, 然后需要识别类型中哪些部分是协程独占的, 哪些部分是
                 可以被多协程共享的. 对于阻塞导致的协程泄漏                L3-2  模式, 可以采用并发阻塞相关的检测工具进行检测, 例如
                      [8]
                 GCatch 等工具.
                    对于  L5-1  模式, 需要匹配   append  函数调用的最后一个实参是否为“slice…”模式         (其中, “…”用于将    slice 赋值
                 给可变参函数的形参), 评估        slice 中所关联的内存大小. 如果      slice 对象所关联的内存较大, 则需要给出警告. 阻碍
                 该模式自动化检测的难点在于如何给出              slice 对象所关联内存大小的估计.
                    对于  N1-1  模式, 需要检查指针类型的返回值接收者是否在使用前进行了非空检查. 对于                      N1-2  模式, 需要检查
                 条件表达式中在指针变量的方法调用之前是否进行了非空检查. 对于                      N1-3  模式, 需要检查指针类型的函数返回值
                 是否在使用前进行了初始化. 这          3  类模式能够较好地进行检测的难点在于, 总是存在情况静态分析无法得知指针
                 是否为空, 从而产生误报.
                    对于未提及的模式, 要实现自动检测需要将函数语义编码到自动检测工具中, 同时还需要考虑控制流的复杂
   249   250   251   252   253   254   255   256   257   258   259