golang 分析调试高阶技巧

本文深入探讨了Golang的高级调试技术,包括使用Golang工具如nm、objdump、pprof、trace进行程序分析,单元测试及代码覆盖率统计,以及借助dlv和gdb进行调试。特别强调了dlv的强大功能,如断点设置、条件断点、堆栈信息查看等,同时也指出了gdb在调试Go程序时的局限性。文章还分享了一些调试小技巧,如如何找到正确断点、查看调用上下文及开启pprof等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


layout: post
title: “golang 调试高阶技巧”
date: 2020-6-03 1:44:09 +0800
categories: golang GC 垃圾回收


  • golang 高阶调试
    • Golang tools
      • nm
      • compile
      • objdump
      • pprof
      • trace
    • 单元测试
      • 执行单元测试
        • go test 运行
        • 编译,运行
      • 统计代码覆盖率
    • 程序 Debug
      • dlv 调试用法
        • 调试二进制
        • 调试进程
        • 调试 core 文件
        • 调试常用语法
          • 系统整理
          • 应用举例
      • gdb 调试
    • 小技巧
      • 不知道怎么断点函数?
      • 不知道调用上下文?
      • 不知道怎么开启 pprof ?
      • 为什么有时候单点调试的时候,总是非预期的执行代码?
    • 总结

golang 高阶调试

本文专注 golang debug 的一些技巧应用,以及相关工具的实用用法,再也不用怕 golang 怎么调试。golang 作为一门现代化语音,出生的时候就自带完整的 debug 手段:

  • golang tools 是直接集成在语言工具里,支持内存分析,cpu分析,阻塞锁分析等;
  • delve,gdb 作为最常用的 debug 工具,让你能够更深入的进入程序调试;
    • delve 当前是最友好的 golang 调试程序,ide 调试其实也是调用 dlv 而已,比如 goland;
  • 单元测试的设计深入到语言设计级别,可以非常方便执行单元测试并且生成代码覆盖率;

Golang tools

golang 从语言原生层面就集成了大量的实用工具,这些都是 Robert Griesemer, Rob Pike, Ken Thompson 这几位大神经验沉淀下的精华。你安装好 golang 之后,执行 go tool 就能看到内置支持的所有工具了。

root@ubuntu:~# go tool
addr2line
asm
buildid
cgo
compile
cover
dist
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vet

我这里专注挑选几个 debug 常用的:

  • nm:查看符号表(等同于系统 nm 命令)
  • objdump:反汇编工具,分析二进制文件(等同于系统 objdump 命令)
  • pprof:指标,性能分析工具
  • cover:生成代码覆盖率
  • trace:采样一段时间,指标跟踪分析工具
  • compile:代码汇编

nm

查看符号表的命令,等同于系统的 nm 命令,非常有用。在断点的时候,如果你不知道断点的函数符号,那么用这个命令查一下就知道了(命令处理的是二进制程序文件)。

# exmple 为你编译的二进制文件
go tool nm ./example

第一列是地址,第二列是类型,第三列是符号:

[图片上传失败…(image-1c9b7a-1594910164396)]

compile

汇编某个文件

go tool compile -N -l -S example.go

你就能看到你 golang 语言对应的汇编代码了(注意了,命令处理的是 golang 代码文本),酷。

objdump

反汇编二进制的工具,等同于系统 objdump(注意了,命令解析的是二进制格式的程序文件)。

go tool objdump example.o
go tool objdump -s DoFunc example.o  // 反汇编具体函数

汇编代码这个东西在 90% 的场景可能都用不上,但是如果你处理过 c 的程序,在某些特殊场景,通过反汇编一段逻辑来推断应用程序行为将是你唯一的出路。因为线上的代码一般都是会开启编译优化,所以这里会导致你的代码对不上。再者,线上不可能让你随意 attach 进程,很多时候都是出 core 了,你就只有一个 core 文件去排查。

pprof

pprof 支持四种类型的分析:

  • CPU :CPU 分析,采样消耗 cpu 的调用,这个一般用来定位排查程序里耗费计算资源的地方;
  • Memroy :内存分析,一般用来排查内存占用,内存泄露等问题;
  • Block :阻塞分析,会采样程序里阻塞的调用情况;
  • Mutex :互斥锁分析,采样互斥锁的竞
<think>嗯,用户之前问过NineData的Docker实现,现在又问Docker多阶构建是什么。看来他们可能是在部署或优化自己的Docker镜像,特别是在构建阶段遇到了问题,比如镜像大小或者依赖管理。 用户可能已经了解了一些Docker的基础知识,现在想深入优化构建过程。多阶构建是一个进阶话题,常用于减少镜像大小和分离构建环境与运行环境。用户可能遇到了构建后的镜像过大,或者构建过程中有太多不必要的依赖被带进生产环境的问题。 需要确认用户是否了解单阶段构建的局限性,比如构建工具和运行时依赖混合在一起,导致镜像臃肿。然后解释多阶构建如何通过多个阶段解决这个问题,第一阶段用于构建,第二阶段仅复制必要的文件,从而减小最终镜像的大小。 同时,用户可能关心实际应用中的例子,比如如何编写多阶段的Dockerfile,以及这样做的好处。需要提供清晰的示例,并对比单阶段和多阶段的区别,突出多阶段的优势,比如安全性、减少攻击面、提高部署效率等。 还要注意用户之前的问题涉及Java和Spring Boot,可能在回答中可以给出相关的例子,比如使用Maven构建,然后用Alpine镜像运行。此外,用户可能想知道最佳实践,比如如何选择基础镜像,如何处理依赖等,这些都需要在回答中涵盖。 最后,确保语言通俗易懂,避免使用过多术语,但又要准确。可能需要检查是否有其他相关知识需要补充,比如多阶段构建的其他用途,比如分离测试和构建,但用户当前的问题集中在构建优化,所以重点放在减小镜像大小和分离环境上。</think>以下是 Docker **多阶段构建**的详细说明: --- ### 一、什么是多阶段构建? Docker 多阶段构建(Multi-stage Build)是一种**优化镜像体积和安全性**的技术。通过将构建过程拆分为多个独立阶段(Stage),最终仅保留运行时所需的必要文件,丢弃构建环境的冗余依赖。 --- ### 二、为什么需要多阶段构建? #### 传统单阶段构建的问题: 1. **镜像臃肿**:构建工具(如 Maven、GCC)和临时文件残留在最终镜像中。 2. **安全风险**:构建环境可能包含敏感信息(如密钥、调试工具)。 3. **依赖混杂**:开发依赖与运行时依赖混合,难以维护。 #### 多阶段构建的优势: - **极简镜像**:最终镜像仅包含编译后的二进制文件/可执行文件。 - **环境隔离**:构建阶段与运行阶段完全分离。 - **安全性提升**:避免泄露构建过程的中间状态。 --- ### 三、工作原理 1. **定义多个 `FROM` 指令** 每个 `FROM` 指令代表一个独立的构建阶段,后续阶段可从前序阶段复制文件。 2. **命名阶段(可选)** 使用 `AS` 为阶段命名,方便后续引用。 3. **最终阶段为运行环境** 只有最后一个 `FROM` 阶段的输出会保留为最终镜像。 --- ### 四、使用示例 #### 场景:构建一个 Spring Boot Java 应用 **单阶段构建的 Dockerfile(问题示例)**: ```dockerfile FROM maven:3.8-jdk-11 # 包含完整的 Maven 和 JDK COPY src /app/src COPY pom.xml /app RUN mvn package # 构建生成 app.jar CMD ["java", "-jar", "/app/target/app.jar"] ``` - **缺点**:最终镜像包含 Maven、JDK 等无用内容,体积可能超过 500MB。 **多阶段构建优化后的 Dockerfile**: ```dockerfile # 阶段 1:构建阶段(使用完整 JDK 和 Maven) FROM maven:3.8-jdk-11 AS builder COPY src /app/src COPY pom.xml /app RUN mvn package -DskipTests # 生成 app.jar # 阶段 2:运行阶段(仅保留 JRE 和编译结果) FROM openjdk:11-jre-slim # 轻量级运行环境 COPY --from=builder /app/target/app.jar /app.jar CMD ["java", "-jar", "/app.jar"] ``` - **效果**:最终镜像仅包含 JRE 和 `app.jar`,体积可缩小至约 150MB。 --- ### 五、关键技术点 1. **跨阶段文件复制** 使用 `COPY --from=<阶段名>` 从前序阶段复制文件: ```dockerfile COPY --from=builder /build/output /app ``` 2. **灵活选择基础镜像** - 构建阶段:使用功能完整的镜像(如 `gcc`, `python:3.9-sdk`)。 - 运行阶段:使用最小化镜像(如 `alpine`, `distroless`)。 3. **多阶段的高级用法** - **并行构建**:多个独立阶段可并行执行(需无依赖关系)。 - **条件复制**:选择性复制不同阶段的文件。 --- ### 六、适用场景 1. **编译型语言**(Go、Java、C++) 分离编译环境与运行环境。 2. **前端项目** 构建阶段安装 npm 依赖并打包,运行阶段使用 Nginx 托管静态文件。 3. **Python 项目** 构建阶段安装 `gcc` 编译依赖,运行阶段仅保留 `.whl` 包。 --- ### 七、最佳实践 1. **命名阶段**:使用 `AS` 提高可读性 ```dockerfile FROM golang:1.19 AS build FROM alpine:3.16 AS runtime ``` 2. **清理中间文件**:在构建阶段结束时删除临时文件 ```dockerfile RUN make build && make clean ``` 3. **使用 `.dockerignore`**:避免无关文件进入构建上下文。 --- ### 八、对比单阶段与多阶段 | | 单阶段构建 | 多阶段构建 | |------------------|------------------|--------------------| | **镜像体积** | 大(含构建工具) | 小(仅运行时依赖) | | **安全性** | 较低(暴露构建过程)| 高(隔离构建环境) | | **构建速度** | 较快(无需分层) | 稍慢(多阶段步骤) | | **维护复杂度** | 低 | 中(需设计阶段逻辑)| --- 通过多阶段构建,可以显著提升 Docker 镜像的**生产环境适用性**,是云原生应用优化的必备技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值