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

1198                                                       软件学报  2026  年第  37  卷第  3  期


                 memory  access  in  Go  programs,  at  25.44%  and  17.63%,  respectively.  This  indicates  the  importance  of  field  sensitivity  and  points-to
                 analysis  in  Go  program  analysis  and  optimization.  Moreover,  implicit  memory  allocation  resulting  from  Go’s  unique  interface  type
                 conversions  is  another  key  area  for  optimization.  Through  manual  analysis  of  130  Issues  involving  memory  leaks,  invalid  memory
                 addresses  or  null  pointer  dereferences,  and  dangling  pointers,  the  study  identifies  10  Issue  patterns,  noting  that  dangling  pointer  problems
                 are  rare  in  Go.  These  Issues  typically  require  around  30  days  for  resolution  but  often  demand  only  a  few  dozen  lines  of  code  changes.
                 The  findings  offer  insights  for  optimizing  Go  programs  and  mitigating  memory  safety  concerns.  Furthermore,  a  linter  is  developed  to
                 detect  the  Issue  pattern,  which  involves  the  assignment  of  a  slice  expression  that  may  lead  to  memory  leaks.  This  tool  identifies  6  Issues
                 in real-world projects, one of which receives positive feedback.
                 Key words:  Go; memory performance; static code analysis; memory safety; empirical study
                    Go  语言是一门新兴现代编程语言, 由          Google 在  2009  年开源. Go  语言凭借其语法特性简洁、内存自动管理、
                 编译速度快、原生支持高并发等特点, 在许多如容器、云原生、数据库、无服务器架构、微服务等新兴软件场
                 景  [1] 中被广泛使用.
                    作为一门兼顾开发效率与执行效率的新兴语言, Go                语言在内存管理方面兼具灵活性与自动化. 一方面, 它支
                 持类似   C/C++的指针和寻址操作, 提供了较高的灵活性; 另一方面, 它通过引入垃圾回收进行自动内存管理, 降低
                 了人工内存管理的成本. Go        的内存管理采用了编译与运行时结合的方式. 在编译时, 利用逃逸分析确定对象的分
                 配位置, 将部分对象分配在栈上以提高程序的内存性能; 在运行时, 垃圾回收器负责动态内存的自动回收, 同时通
                 过检测机制在一定程度上避免诸如内存泄漏、空指针解引用等安全问题. 然而, 这套独特的内存访问与管理机制,
                 也使得 Go  程序面临独特的内存安全和性能问题.
                    Go  语言的特殊内存管理机制虽然带来了便捷性, 但也存在一定的性能问题和内存安全隐患, 这些问题引发了
                 社区和学术界的讨论和改进尝试.
                                                                                                 [2]
                    一方面, Go   的垃圾回收机制在处理生命期相似的对象时效率有限. 例如, Go                   社区提案    Issue#51317 建议引
                 入  arena 机制, 通过整体分配和释放生命期相近对象的内存区域来提升性能, 该功能已在                       Go 1.20 中实验性支持.
                 此外, 一些编程模式也可能引发性能问题. Wang            等人  [3] 发现, 将对象转换为接口并作为实参传递的操作可能导致
                 不必要的堆分配, 为此他们用正则表达式识别相应的模式并绕过逃逸分析来减少堆内存分配量. Ding                              等人  [4] 研究
                 表明, Go  的逃逸分析算法存在保守建模问题, 导致一些不必要的堆内存分配, 他们通过为逃逸分析引入域敏感性
                 和指向分析, 能够在增加较小编译开销的情况下提升分析精度和程序性能. Peng                       等人  [5] 则通过显式识别和回收短
                 生命期的堆对象, 减少了垃圾回收的开销并提高了内存利用效率.
                    另一方面, 尽管     Go  语言引入了垃圾回收和运行时检测机制, 但却无法完全避免内存安全问题. 例如, 在远程
                                                [7]
                                  [6]
                 过程调用框架 grpc-go  中的 Issue#4758 中, 在客户端连接数量减少、服务负载降低后, 内存未能按预期减少, 导
                 致内存泄漏. 此外, 并发问题也是开发中常见的挑战. Liu             等人  [8]  使用  GCatch 工具发现了 149 个并发阻塞问题, 而
                 Veileborg  等人  [9] 进一步发现了 104 个并发阻塞问题. 这些表明, 尽管      Go  的内存管理机制已经相对完善, 但仍有改
                 进空间, 开发者需要关注并应对相关问题.
                    针对上述内存性能与安全问题, 静态代码模式识别与优化往往是有效的解决方案. 例如, Selakovic 等人                           [10] 总
                 结了  JavaScript 性能问题的常见代码模式, 指导开发者和分析人员进行优化. Liu                等人  [8] 利用  GCatch  工具识别信
                 道阻塞问题的代码模式, 并通过          GFix  自动修复. Chabbi 等人  [11] 则针对数据竞争问题总结了相关的代码模式. Go
                 语言社区也存在较多通过规则和模式匹配的工具 (如                 Staticcheck [12] 、go vet [13] 、golangci-lint [14] 、gosec [15] 、revive [16]
                 等), 用于检测非内存安全问题和并发问题. 然而, 针对             Go  的内存性能优化和非并发类内存安全问题的模式识别和
                 检测的工作仍较少.
                    基于以上观察, 希望通过静态代码分析, 对             Go  语言的内存性能优化问题和非并发类内存安全问题进行实证
                 研究. 研究将探索     Go  语言的内存访问特征及其问题模式, 帮助开发者识别并避免潜在的问题, 并为社区提供有关
                 内存管理优化的见解, 推动        Go  工具链的改进.
                    本文主要围绕以下       3  个研究问题 (RQ) 展开实证探究.
   230   231   232   233   234   235   236   237   238   239   240