LiSheng's blog LiSheng's blog
首页
笔记
个人简历
随笔集
GitHub (opens new window)
首页
笔记
个人简历
随笔集
GitHub (opens new window)
  • golang

    • 并发编程

    • 内存管理

      • gc整体过程
      • GC触发条件
      • GC相关
      • 内存相关
      • 数组和切片的区别
      • new和make
      • go defer
      • context
      • channel
      • go map
      • interface
      • 对象系统
      • rune 类型
      • 字符串拼接的几种方式
    • cplus

    • leetcode

    • 存储技术

    • 分布式系统

    • 计算机网络

    • Linux操作系统

    • Redis

    • 其他

    • 笔记
    • golang
    • 内存管理
    lisheng
    2024-09-10
    目录

    内存相关

    1、谈谈内存泄露,什么情况下内存会泄露?怎么定位排查内存泄漏问题? 2、知道 golang 的内存逃逸吗?什么情况下会发生内存逃逸? 3、请简述 Go 是如何分配内存的?Channel 分配在栈上还是堆上?哪些对象分配在堆上,哪些对象分配在栈上? 4、介绍一下大对象小对象,为什么小对象多了会造成 gc 压力?

    # 1. Go 语言的内存分配

    • 问题: Go 语言中内存是如何分配的?栈上分配和堆上分配有什么区别?
    • 回答要点:
      • 在 Go 语言中,局部变量通常分配在栈上,而逃逸到函数外部或长生命周期的对象分配在堆上。
      • 栈分配是自动管理的,当函数返回时栈内存会自动释放,速度非常快。
      • 堆分配需要垃圾回收器的管理,因此开销较大,但允许对象在函数返回后继续存在。

    # 2. 逃逸分析

    • 问题: 解释什么是逃逸分析,Go 编译器如何通过逃逸分析来决定内存的分配位置?
    • 回答要点:
      • 逃逸分析是编译器确定变量是否在栈上分配还是堆上分配的过程。
      • 如果一个变量在函数外部被引用或生命周期超过函数范围,它将“逃逸”到堆上。
      • 逃逸分析的目的是减少堆内存分配,优化性能。

    # 3. 内存对齐

    • 问题: 什么是内存对齐?在 Go 中如何处理内存对齐问题?
    • 回答要点:
      • 内存对齐是指数据在内存中的存储地址应符合特定的边界要求,这样可以提高内存访问效率。
      • Go 的编译器会自动处理内存对齐,开发者通常不需要手动干预。
      • 对齐可以影响结构体的内存布局,有时会产生填充字节以保证结构体的字段按最优方式对齐。

    # 4. 垃圾回收机制

    • 问题: 请解释 Go 语言的垃圾回收机制,它如何影响内存管理?
    • 回答要点:
      • Go 语言使用的是标记-清除(mark-and-sweep)垃圾回收机制。
      • GC 自动管理堆内存的回收,通过标记不再使用的对象并清除它们来释放内存。
      • GC 会影响内存管理的性能,特别是在高分配率或长生命周期对象较多的程序中。

    # 5. 内存泄漏

    • 问题: 什么是内存泄漏?在 Go 语言中如何防止内存泄漏?
    • 回答要点:
      • 内存泄漏是指由于程序中的某些对象没有被正确释放,导致内存持续占用。
      • Go 语言的内存泄漏通常发生在 Goroutine 泄漏、未关闭的通道、或持有对不再需要的数据的引用。
      • 可以使用 pprof 等工具检测内存泄漏,确保资源得到及时释放。

    # 6. 内存分配器的设计

    • 问题: Go 语言的内存分配器是如何设计的?如何优化内存分配?
    • 回答要点:
      • Go 的内存分配器基于 tcmalloc 设计,使用不同大小的内存池来处理不同的分配请求。
      • 小对象(<=32KB)从 per-P 分配缓存中分配,大对象直接从堆分配。
      • 优化内存分配的关键是减少频繁的小对象分配、减少内存碎片和重用对象。

    # 7. Go 语言中的 sync.Pool

    • 问题: 什么是 sync.Pool?它在内存管理中起到什么作用?
    • 回答要点:
      • sync.Pool 是一个用于存储临时对象的内存池,目的是减少垃圾回收的负担。
      • 使用 sync.Pool 可以在高并发环境下重用对象,减少内存分配和垃圾回收的次数。
      • sync.Pool 中的对象生命周期较短,并且在 GC 时会被清理。

    # 8. 内存分配的最佳实践

    • 问题: 在 Go 语言中,有哪些内存分配的最佳实践可以提高程序的性能?
    • 回答要点:
      • 尽量减少堆分配,利用栈分配来提高性能。
      • 重用对象,使用 sync.Pool 或其他对象池来减少内存分配开销。
      • 避免过度分配大对象,尽量使用小对象组合以优化内存使用。
      • 控制垃圾回收频率,使用 GOGC 调整垃圾回收参数以平衡内存使用和性能。

    # 9. 内存管理与并发

    • 问题: 在高并发程序中,如何管理内存以避免内存爆炸和性能下降?
    • 回答要点:
      • 控制 Goroutine 的数量,避免大量 Goroutine 同时运行导致内存占用过高。
      • 使用 sync.Pool 来重用对象,减少频繁的内存分配。
      • 在并发处理中,避免持有大对象的引用,尽可能减少内存争用。

    # 10. 内存分配与逃逸分析的关系

    • 问题: 如何通过代码优化减少变量的逃逸,进而优化内存管理?
    • 回答要点:
      • 检查函数返回的局部变量,避免让变量逃逸到堆上。
      • 使用指针可能导致变量逃逸,尽量在局部范围内使用值传递。
      • 在编译时可以通过 go build -gcflags '-m' 查看逃逸分析报告,识别和优化逃逸的变量。

    # 11.Channel 分配在栈上还是堆上?哪些对象分配在堆上,哪些对象分配在栈上?

    在 Go 语言中,Channel 通常分配在 堆上。这是因为 Channel 是一个引用类型,通常会在函数之间传递,并且生命周期可能超过创建它的函数。这种情况下,Go 的逃逸分析会将它分配到堆上,以确保它在函数返回后仍然可用。

    # 分配在堆上的对象

    以下情况的对象通常会分配到堆上:

    1. 被外部引用的局部变量:如果一个局部变量在函数外部被引用(如通过返回指针或闭包),它会逃逸到堆上。
    2. 引用类型:如 Channel、切片(slice)、映射(map)、接口(interface)、函数类型(function),这些类型在需要跨函数作用域使用时通常会分配在堆上。
    3. 大对象:如果对象较大,编译器可能会选择将它分配到堆上,以避免占用过多的栈空间。
    4. 需要长生命周期的对象:当一个对象的生命周期超过创建它的函数时,通常会分配在堆上。

    # 分配在栈上的对象

    以下情况的对象通常会分配到栈上:

    1. 局部变量:如果一个局部变量只在函数内部使用,并且不会被外部引用,它通常会分配在栈上。
    2. 短生命周期的对象:当一个对象的生命周期在函数内部结束时,编译器通常会将其分配在栈上,以便在函数返回时自动释放内存。
    3. 不会逃逸的对象:在编译时通过逃逸分析确定不会逃逸出函数作用域的对象,会被分配在栈上。

    # 逃逸分析

    Go 编译器在编译时会进行 逃逸分析,来决定对象应该分配在栈上还是堆上。这个分析决定了内存的分配位置,以便在性能和内存管理之间取得平衡。

    你可以使用 go build -gcflags '-m' 命令查看编译时的逃逸分析结果,了解哪些变量逃逸到堆上,哪些留在栈上。这对于优化内存管理非常有帮助。

    编辑 (opens new window)
    上次更新: 2024/09/13, 11:59:12
    GC相关
    数组和切片的区别

    ← GC相关 数组和切片的区别→

    最近更新
    01
    ceph分布式存储-对象存储(RGW)搭建
    10-27
    02
    ceph分布式存储-集群客户端连接
    10-27
    03
    ceph分布式存储-管理crushmap
    10-27
    更多文章>
    Theme by Vdoing
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式