golang内存泄漏

golang也用了好几年了,趁着有空 整理归纳下,以后忘了好看下
一般认为 Go 10次内存泄漏,8次goroutine泄漏,1次是真正内存泄漏,还有1次是cgo导致的内存泄漏
1:环境
go1.20
win10
2:goroutine泄漏
单个Goroutine占用内存,可参考Golang计算单个Goroutine占用内存, 在不发生栈扩张情况下, 新版本Go大概单个goroutine 占用2.6k左右的内存
Goroutine 泄露的常见原因
1>. 从 channel 里读,但是同时没有写入操作
2> 向 无缓冲 channel 里写,但是同时没有读操作
3> 向已满的 有缓冲 channel 里写,但是同时没有读操作
4> select操作在所有的case上都阻塞
5> goroutine进入死循环或死锁,一直结束不了

处理
<1><2><3> 少撒加撒,没什么解释的
<4> 查看 case 阻塞 原因 有没有缓冲什么的,为什么都阻塞,有没有超时机制
<5> 为什么死循环或死锁
来个demo

package mainimport ("fmt""net/http"_ "net/http/pprof""sync/atomic""time"
)func pprofServer() {ip := "0.0.0.0:6060"if err := http.ListenAndServe(ip, nil); err != nil {fmt.Printf("start pprof failed on %s\n", ip)}
}
// 所有chan 阻塞
func goroutineblock() {ch1 := make(chan string) // 无缓冲channelch2 := make(chan string) // 无缓冲channelgo func() {select {case <-ch1:fmt.Println("output1")case <-ch2:fmt.Println("output2")}}()
}

在这里插入图片描述

补充下 pprof
通过 http://localhost:6060/debug/pprof/CMD 获取对应的采样数据。支持的 CMD 有:
goroutine: 获取程序当前所有 goroutine 的堆栈信息。
heap: 包含每个 goroutine 分配大小,分配堆栈等。每分配 runtime.MemProfileRate(默认为512K) 个字节进行一次数据采样。
threadcreate: 获取导致创建 OS 线程的 goroutine 堆栈
block: 获取导致阻塞的 goroutine 堆栈(如 channel, mutex 等),使用前需要先调用 runtime.SetBlockProfileRate
mutex: 获取导致 mutex 争用的 goroutine 堆栈,使用前需要先调用 runtime.SetMutexProfileFraction

GC的触发场景
在这里插入图片描述

0:gcTriggerHeap 程序检测到距上次 GC 内存分配增长超过一定比例时(默认 100%)触发,就是内存翻倍就GC
heapLive 表示当前堆中存活(正在使用)的对象的总大小。
它反映了程序当前实际使用的堆内存量。
随着程序分配新对象和释放旧对象,这个值会动态变化
gcPercent 是一个控制GC触发频率的参数。
默认值是100,表示当堆内存增长到上次GC后的2倍时触发新的GC。
可以通过环境变量 GOGC 或运行时函数 debug.SetGCPercent() 来调整。

1:gcTriggerTime 从上次GC后间隔时间达到了runtime.forcegcperiod 时间
// This is a variable for testing purposes. It normally doesn’t change.
var forcegcperiod int64 = 2 * 60 * 1e9
2:gcTriggerCycle 用户主动调用runtime.GC().

GoV1.8 三色标记法+混合写屏障法
参考 https://zhuanlan.zhihu.com/p/14541819173
垃圾回收(Garbage Collection,简称GC)是编程语言中提供的自动的内存管理机制,自动释放不需要的对象,让出存储器资源,无需程序员手动执行。
​ Golang中的垃圾回收主要应用三色标记法,GC过程和其他用户goroutine可并发运行,但需要一定时间的STW(stop the world),STW的过程中,CPU不执行用户代码,全部用于垃圾回收,这个过程的影响很大,Golang进行了多次的迭代优化来解决这个问题。

三色并发标记法
三色标记法 实际上就是通过三个阶段的标记来确定清楚的对象都有哪些.
1> 就是只要是新创建的对象,默认的颜色都是标记为“白色”.
2> 每次GC回收开始, 然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入“灰色”集合。
3> 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合
4> 重复第三步, 直到灰色中无任何对象.
5> 回收所有的白色标记表的对象. 也就是回收垃圾.
可以看出,在三色标记法中,导致对象丢失的有两个条件:
1> 一个白色对象被黑色对象引用**(白色被挂在黑色下)**
2> 灰色对象与它之间的可达关系的白色对象遭到破坏**(灰色同时丢了该白色)**

关于 stw
Go的STW持续时间
Go的垃圾回收器通过使用并发标记和后台并发清除来尽量减少STW的时间。这意味着在大多数情况下,Go程序不会因为垃圾回收而完全停止。然而,在某些情况下,比如在高负载或大量内存分配时,Go的垃圾回收器可能会触发一个较长的STW暂停。
较短的STW:在正常情况下,特别是在使用了Go 1.3及以后版本的程序中,STW暂停通常很短,可能只有几毫秒。
较长的STW:在一些极端情况下,如果内存分配非常快或者堆的大小增长非常快,可能会触发一个较长的STW暂停。这通常发生在堆的增长超过了预设的阈值,并且系统需要一次性清理大量对象时。
如何管理和减少STW时间
优化内存使用:通过减少内存分配和优化数据结构的使用,可以降低垃圾回收的频率和STW的必要性。
调整GC参数:Go提供了多个GC调优参数(例如GOGC),可以用来调整垃圾回收的行为。例如,增加GOGC的值可以减少垃圾回收的频率,但可能会增加STW的持续时间。
使用runtime.ReadMemStats监控内存使用:通过监控内存使用情况,可以更好地理解何时会发生垃圾回收,并据此优化代码。

在补充下 Golang中协程调度器
参考 https://blog.csdn.net/tiancityycf/article/details/103857524
三个必知的核心元素。(G、M、P)
G:Goroutine的缩写,一个G代表了对一段需要被执行的Go语言代码的封装
M:Machine的缩写,一个M代表了一个内核线程,等同于系统线程
P:Processor的缩写,一个P代表了M所需的上下文环境

G需要绑定在M上才能运行;
M需要绑定P才能运行;
上所述,一个G的执行需要M和P的支持。一个M在于一个P关联之后就形成一个有效的G运行环境 【内核线程 + 上下文环境】。每个P都含有一个 可运行G的队列【runq】。队列中的G会被一次传递给本地P关联的M并且获得运行时机。
M 与 P 总是一对一,P 与 G 总是 一对多, 而 一个 G 最终由 一个 M 来负责运行。

简单的来说,一个G的执行需要M和P的支持。一个M在与一个P关联之后形成了一个有效的G运行环境【内核线程 + 上下文环境】。每个P都会包含一个可运行的G的队列 (runq )。队列中的G会被一次传递给本地P关联的M并且获得运行时机。
M 与 P 总是一对一,P 与 G 总是 一对多, 而 一个 G 最终由 一个 M 来负责运行。
调度器的有两大思想:

复用线程:协程本身就是运行在一组线程之上,不需要频繁的创建、销毁线程,而是对线程的复用。在调度器中复用线程还有2个体现:1)work stealing,当本线程无可运行的G时,尝试从其他线程绑定的P偷取G,而不是销毁线程。2)hand off,当本线程因为G进行系统调用阻塞时,线程释放绑定的P,把P转移给其他空闲的线程执行。

利用并行:GOMAXPROCS设置P的数量,当GOMAXPROCS大于1时,就最多有GOMAXPROCS个线程处于运行状态,这些线程可能分布在多个CPU核上同时运行,使得并发利用并行。另外,GOMAXPROCS也限制了并发的程度,比如GOMAXPROCS = 核数/2,则最多利用了一半的CPU核进行并行。

调度器的两小策略:
抢占:在coroutine中要等待一个协程主动让出CPU才执行下一个协程,在Go中,一个goroutine最多占用CPU 10ms,防止其他goroutine被饿死,这就是goroutine不同于coroutine的一个地方。
全局G队列:在新的调度器中依然有全局G队列,但功能已经被弱化了,当M执行work stealing从其他P偷不到G时,它可以从全局G队列获取G。

3:其他情况
1>slice、string 切片 误用造成内存泄漏 个人认为不应该叫泄漏 应该叫 浪费,就是你只需要吃一口饭就饱了,但你盛了一大碗饭

func main() {go pprofServer()time.Sleep(5 * time.Second)//for i := 0; i < 30; i++ {//	goroutineblock()////}//test2s0 := sliceleak(getStringWithLengthOnHeap(1 << 20)) // 1M bytesprintln("finish")  //第一次 调用  go tool pprof -http=:8081 http://localhost:6060/debug/pprof/heap time.Sleep(10 * time.Second)s0 = ""runtime.GC()  //gcTriggerTime  等2分钟太久了,手动GC一次//第2次 调用  go tool pprof -http=:8081 http://localhost:6060/debug/pprof/heap select {}println("finish2", s0)
}
// 2切片   len(s1) >3
func sliceleak(s1 string) string {s0 := s1[:3]return s0
}func getStringWithLengthOnHeap(length int) string {if length < 0 {length = 0 // 处理负长度的情况,避免创建负长度的切片}bytes := make([]byte, length) // 创建一个指定长度的字节切片for i := range bytes {        // 使用空格填充(或根据需要修改填充内容)bytes[i] = ' '}return string(bytes) // 将字节切片转换为字符串
}

一次在 println(“finish”) 后 time.Sleep(10 * time.Second) 前
第2次在等20秒后再调用的 控制再手动gc 后调用
切片浪费的内存也会释放,无非是 没释放前,浪费了,所以切片的 如果浪费很多,用重新分配后小的再copy过去,浪费不多,可以无视
在这里插入图片描述
2>time.After()的使用

func timeleak() {chs := make(chan int, 60)go func() {var  num = 0for {num ++chs <- num }}()for true {select {case <-time.After(time.Second * 60): //定时任务未到期之前,是不会被gc清理的fmt.Printf("time.After:%v", time.Now().Unix())case num := <-chs:fmt.Printf("print:num %v\n", num )}}
//可以这么修改//delay := time.NewTimer(time.Second * 60)//defer delay.Stop()//for true {//	delay.Reset(time.Second * 60)//	select {//	case <-delay.C://		fmt.Printf("time.After:%v", time.Now().Unix())//	case v := <-chs://		fmt.Printf("print:%v\n", v)//	}//}}

print:693435
print:693436
print:693437
print:693438

间隔 执行了2次

在这里插入图片描述

如改成

func timeleak() {chs := make(chan int, 100)go func() {var i = 0for {i++chs <- iif i%10 == 0 {time.Sleep(time.Millisecond)}}}()for true {select {case <-time.After(time.Second * 1000): //定时任务未到期之前,是不会被gc清理的fmt.Printf("time.After:%v", time.Now().Unix())case v := <-chs:if v%1000 == 0 {fmt.Printf("print:%v\n", v)}}}
}

在这里插入图片描述
从 10000内执行一次 第2次 大概是 40000-50000间
内存泄漏速度下降 了好多,泄漏的速度跟 case 执行速度又关

如果用default 如下,内存泄漏 更快,不用default time.After 会阻塞,用了,不阻塞了,死的更快
for loop 下的 select 中 default 需要慎用

func timeleak2() {var i int32 = 0for {select {case <-time.After(time.Second * 1000): //定时任务未到期之前,是不会被gc清理的fmt.Printf("time.After:%v", time.Now().Unix())default:i++if i < 50000 {fmt.Println("i=", i)}}}
}

在这里插入图片描述

3> 可以参考 https://blog.csdn.net/qq_38609643/article/details/144963265
这里就不一一 试了
(1)未及时释放的对象引用
(2)循环引用
(3)未关闭的资源(文件、网络连接等)
(4) 闭包引用外部变量
(5)使用了 sync.Pool 但没有清理
(6)不合理的 defer 使用

4>GC 频繁 排查 参考 https://zhuanlan.zhihu.com/p/18966775221

4: 生成svg
1:http://localhost:6060/debug/pprof/heap 生成heap文件
2:把heap 文件放到 执行文件同一目录
3:https://graphviz.org/download/ 下载 graphviz-12.2.1 (64-bit) ZIP archive [sha256] 配置 path ##路径不要有中文或其他标点符号 有时识别不了
3: go tool pprof heap
4:执行 svg 命令 生成 profile001.svg
5:浏览器打开

other 差异对比
差异对比 eg:
go tool pprof -base C:\Users\Administrator\pprof\pprof.testmemory.exe.alloc_objects.alloc_space.inuse_objects.inuse_space.008.pb.gz C:\Users\Administrator\pprof\pprof.testmemory.exe.alloc_objects.alloc_space.inuse_objects.inuse_space.009.pb.gz

5:如果觉得有用,麻烦点个赞,加个收藏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23304.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机毕业设计SpringBoot+Vue.jst房屋租赁系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

DevEco Studio常用快捷键以及如何跟AndroidStudio的保持同步

DevEco Studio快捷键 DevEco Studio是华为推出的用于开发HarmonyOS应用的集成开发环境&#xff0c;它提供了丰富的快捷键以提高开发效率&#xff0c;以下为你详细介绍不同操作场景下的常用快捷键&#xff1a; 通用操作快捷键 操作描述Windows/Linux 快捷键Mac 快捷键打开设置窗…

qt5实现表盘的旋转效果,通过提升QLabel类

因为工作需要&#xff0c;需要实现温度的表盘展示效果 实现思路&#xff1a; 通过提示声QLabel控价类&#xff0c;实现报盘的旋转和展示效果 1. 编写一个QLabel的类MyQLabel,实现两个方法 1. void paintEvent(QPaintEvent *event); //重绘函数 2. void valueChanged(int va…

vscode settings(一):全局| 用户设置常用的设置项

参考资料 Visual Studio Code权威指南 by 韩骏 一. 全局设置与用户设置 1.1 Vscode支持两种不同范围的设置 用户设置(User Settings)&#xff1a;这是一个全局范围的设置&#xff0c;会应用到所有的Visual Studio Code实例中。工作区设置(Workspace Settings)&#xff1a;设…

C# 将非托管Dll嵌入exe中(一种实现方法)

一、环境准备 电脑系统&#xff1a;Windows 10 专业版 20H2 IDE&#xff1a;Microsoft Visual Studio Professional 2022 (64 位) - Current 版本 17.11.4 其他&#xff1a; 二、测试目的 将基于C创建DLL库&#xff0c;封装到C#生成的exe中。 一般C创建的库&#xff0c;在…

在 Mac mini M2 上使用Docker快速部署MaxKB:打造本地知识库问答系统

随着大语言模型的广泛应用&#xff0c;知识库问答系统逐渐成为提升工作效率和个人学习的有力工具。MaxKB是一款基于LLM&#xff08;Large Language Model&#xff09;大语言模型的知识库问答系统&#xff0c;支持多模型对接、文档上传和自动爬取等功能。本文将详细介绍如何在Ma…

Jenkins上无法查看已成功生成的Junit报告

如果你已确认 JUnit 报告在工作空间中被成功生成&#xff0c;但在 Jenkins 构建页面上却看不到 "Test Result" 或 "Test Report" 的链接&#xff0c;这通常意味着 Jenkins 没有正确地配置用来处理和显示这些报告的步骤。这里有几个可能的原因和解决方法&am…

vue+element-plus简洁完美实现淘宝网站模板

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.详情 4.购物车 5.登陆页 三、源码实现 1.路由配置 2.依赖包 四、总结 一、项目介绍 项目在线预览&#xff1a;点击访问 本项目为vue项目&#xff0c;参考淘宝官方样式为主题来设计元素&#xff0c;简洁美观&…

stm32hal库寻迹+蓝牙智能车(STM32F103C8T6)

简介: 这个小车的芯片是STM32F103C8T6&#xff0c;其他的芯片也可以照猫画虎,基本配置差不多,要注意的就是,管脚复用,管脚的特殊功能,(这点不用担心,hal库每个管脚的功能都会给你罗列,很方便的.)由于我做的比较简单,只是用到了几个简单外设.主要是由带霍尔编码器电机的车模,电机…

红队内网攻防渗透:内网渗透之内网对抗:实战项目VPC2打靶父子域三层路由某绒免杀下载突破约束委派域控提权

红队内网攻防渗透 实战网络攻防靶场记录1.靶机配置信息讲解2.靶场渗透完整流程2.1 入口点:192.168.139.130(win2008 R2)2.1.1 tomcat后台war包获取权限2.1.2 tomcat使用后门上线CS平台2.1.3 信息收集获取数据库密码2.2 入口点横向:192.168.10.11 (win2012 SQL)2.2.1 SQLs…

C语言【指针篇】(一)

前言 指针基础概念理解&#xff0c;从底层出发理解指针 C语言【指针篇】&#xff08;一&#xff09; 前言正文1. 内存和地址1.1 内存1.2 究竟该如何理解编址 2. 指针变量和地址2.1 取地址操作符(&)2.2 指针变量和解引用操作符(*)2.3 指针变量的大小 3. 指针变量类型的意义…

【每日八股】Redis篇(二):数据结构

Redis 数据类型&#xff1f; 主要有 STRING、LIST、ZSET、SET 和 HASH。 STRING String 类型底层的数据结构实现主要是 SDS&#xff08;简单动态字符串&#xff09;&#xff0c;其主要应用场景包括&#xff1a; 缓存对象&#xff1a;可以用 STRING 缓存整个对象的 JSON&…

文章精读篇——用于遥感小样本语义分割的可学习Prompt

题目&#xff1a;Learnable Prompt for Few-Shot Semantic Segmentation in Remote Sensing Domain 会议&#xff1a;CVPR 2024 Workshop 论文&#xff1a;10.48550/arXiv.2404.10307 相关竞赛&#xff1a;https://codalab.lisn.upsaclay.fr/competitions/17568 年份&#…

游戏引擎学习第119天

仓库:https://gitee.com/mrxiao_com/2d_game_3 上一集回顾和今天的议程 如果你们还记得昨天的进展&#xff0c;我们刚刚完成了优化工作&#xff0c;目标是让某个程序能够尽可能快速地运行。我觉得现在可以说它已经快速运行了。虽然可能还没有达到最快的速度&#xff0c;但我们…

HybridCLR+Adressable+Springboot热更

本文章会手把手教大家如何搭建HybridCLRAdressableSpringboot热更。 创作不易&#xff0c;动动发财的小手点个赞。 安装华佗 首先我们按照官网的快速上手指南搭建一个简易的项目&#xff1a; 快速上手 | HybridCLR 注意在热更的代码里添加程序集。把用到的工具放到程序集里…

多无人机协同路径规划(论文+仿真)

在现代技术的快速发展下&#xff0c;飞行器的种类也越来越多了&#xff0c;他们的应用场景和应用功能也越来越完善和复杂。举例来说&#xff0c;ps-x625型号就是大疆无人机生产的就是在植物保护方面有很好的应用&#xff0c;宝鸡的兴义生产的X8型号无人机在航空领域有很大突破&…

CentOS环境变量配置+解析

环境变量的作用就是让系统快速通过你的命令找到你的可执行程序&#xff0c;windows系统里也同理&#xff0c;也就是你每次输入个命令&#xff0c;系统就会找环境变量里到底有没有叫这个命令进程的 一、环境变量配置 1.编辑配置文件 vim /etc/profile export PATH$PATH:$JAVA…

einops测试

文章目录 1. einops2. code3. pytorch 1. einops einops 主要是通过爱因斯坦标记法来处理张量矩阵的库&#xff0c;让矩阵处理上非常简单。 conda : conda install conda-forge::einopspython: 2. code import torch import torch.nn as nn import torch.nn.functional as…

Unity教程(二十一)技能系统 基础部分

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

Docker:Docker从入门到精通(一)- Docker简介

一、前言 通过本专栏的学习&#xff0c;我们将了解   1. 掌握Docker基础知识&#xff0c;能够理解Docker镜像与容器的概念   2. 完成Docker安装与启动   3. 掌握Docker镜像与容器相关命令   4. 掌握Tomcat Nginx 等软件的常用应用的安装   5. 掌握docker迁移与备份相…