Golang Go语言中请问这段代码会内存泄漏吗?

发布于 1周前 作者 bupafengyu 来自 Go语言

Golang Go语言中请问这段代码会内存泄漏吗?


import (
“fmt”
“runtime”
“strconv”
“time”
)

func do() { max := 2100000 item := 11511 var a []int for range make([]struct{}, max) { a = append(a, item) } var sitem []string for range make([]struct{}, max) { sitem = append(sitem, strconv.Itoa(item)) } fmt.Println(len(sitem)) runtime.GC() }

func main() { for range make([]struct{}, 10) { go do() } time.Sleep(time.Hour) }``` 我个逻辑线上的代码简化版,占用内存 1.1G…怎么会这样, 是没有被 GC 掉吗?


更多关于Golang Go语言中请问这段代码会内存泄漏吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

14 回复

如果想要立即释放,可以调用 runtime/debug 里的 FreeOSMemory()

更多关于Golang Go语言中请问这段代码会内存泄漏吗?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


em…也试了, 内存也没有减少

试了一下, 占用内存从 1000M 在 5 秒左右掉到了 744M 10 秒左右 434M 15 秒左右 239M 20 秒就只有 99M 了 最后稳定在 3M 内存占用 没发现 gc 失败啊… go 最新版本 1.11.2 goland 也是最新版本 2018.3

请问你用什么工具看内存的? 我对 htop 是不是有点误解…

我在 mac 上测试的, 好像是因为 thread 没有退出.
Sampling process 19768 for 3 seconds with 1 millisecond of run time between samples
Sampling completed, processing symbols…
Analysis of sampling ___go_build_add_go (pid 19768) every 1 millisecond
Process: ___go_build_add_go [19768]
Path: /private/var/folders/wd/vt73dmmj5y38hft8kg5l1wgm0000gq/T/___go_build_add_go
Load Address: 0x1000000
Identifier: ___go_build_add_go
Version: ???
Code Type: X86-64
Parent Process: goland [14064]

Date/Time: 2018-12-06 21:33:47.174 +0800
Launch Time: 2018-12-06 21:33:00.224 +0800
OS Version: Mac OS X 10.13.6 (17G3025)
Report Version: 7
Analysis Tool: /usr/bin/sample

Physical footprint: 1.2G
Physical footprint (peak): 1.2G
----

Call graph:
2580 Thread_15197711 DispatchQueue_1: com.apple.main-thread (serial)
+ 2580 runtime.asmcgocall (in ___go_build_add_go) + 112 [0x1050da0]
+ 2580 runtime.pthread_cond_timedwait_relative_np_trampoline (in ___go_build_add_go) + 20 [0x1053204]
+ 2580 _pthread_cond_wait (in libsystem_pthread.dylib) + 789 [0x7fff5779a5c2]
+ 2580 __psynch_cvwait (in libsystem_kernel.dylib) + 10 [0x7fff575d1a16]
2580 Thread_15197713
+ 2580 thread_start (in libsystem_pthread.dylib) + 13 [0x7fff57798bf9]
+ 2580 _pthread_start (in libsystem_pthread.dylib) + 377 [0x7fff5779950d]
+ 2580 runtime.mstart_stub (in ___go_build_add_go) + 46 [0x10530ce]
+ 2580 runtime.mstart (in ___go_build_add_go) + 102 [0x102b9d6]
+ 2580 runtime.mstart1 (in ___go_build_add_go) + 230 [0x102bad6]
+ 2580 runtime.sysmon (in ___go_build_add_go) + 371 [0x10330b3]
+ 2580 runtime.notetsleep (in ___go_build_add_go) + 105 [0x1009499]
+ 2580 runtime.notetsleep_internal (in ___go_build_add_go) + 269 [0x10092cd]
+ 2580 runtime.semasleep (in ___go_build_add_go) + 271 [0x1024e3f]
+ 2580 runtime.pthread_cond_timedwait_relative_np (in ___go_build_add_go) + 81 [0x1043301]
+ 2580 runtime.asmcgocall (in ___go_build_add_go) + 173 [0x1050ddd]
+ 2580 runtime.pthread_cond_timedwait_relative_np_trampoline (in ___go_build_add_go) + 20 [0x1053204]
+ 2580 _pthread_cond_wait (in libsystem_pthread.dylib) + 789 [0x7fff5779a5c2]
+ 2580 __psynch_cvwait (in libsystem_kernel.dylib) + 10 [0x7fff575d1a16]
2580 Thread_15197714
+ 2580 runtime.mcall (in ___go_build_add_go) + 91 [0x104f52b]
+ 2580 runtime.goexit0 (in ___go_build_add_go) + 498 [0x102f552]
+ 2580 runtime.schedule (in ___go_build_add_go) + 314 [0x102eb6a]
+ 2580 runtime.findrunnable (in ___go_build_add_go) + 1244 [0x102e05c]
+ 2580 runtime.stopm (in ___go_build_add_go) + 227 [0x102cee3]
+ 2580 runtime.notesleep (in ___go_build_add_go) + 227 [0x1009163]
+ 2580 runtime.semasleep (in ___go_build_add_go) + 133 [0x1024db5]
+ 2580 runtime.pthread_cond_wait (in ___go_build_add_go) + 81 [0x1043291]
+ 2580 runtime.asmcgocall (in ___go_build_add_go) + 173 [0x1050ddd]
+ 2580 runtime.pthread_cond_wait_trampoline (in ___go_build_add_go) + 16 [0x10531e0]
+ 2580 _pthread_cond_wait (in libsystem_pthread.dylib) + 732 [0x7fff5779a589]
+ 2580 __psynch_cvwait (in libsystem_kernel.dylib) + 10 [0x7fff575d1a16]
… 一共重复了 10 个 thread. 我在研究一下

巧合, 里面的内容和我的业务逻辑没关系…

我在 main 函数里面的循环 sleep,一秒创建一个协程的情况下,内存基本上稳定在第一次协程分配的值。应该是主程序 sleep 的情况下,并没有其他的对象要分配,所以就不回收了。

你是对的, 我把最后那个 sleep 一个小时, 改成了 for{}, 就可以回收了. 谢谢

  • -我也基本上维持在 1 - 1.1g 左右的内存占用

测了一下你的代码,稳定一会儿 1.2g,后来忘记看了,过了十来分钟看一下 50M 了.

就是 htop 啊 稍微过一会就能看到内存急剧下降 2018 款 MacBookpro 系统是最新的 Mojave 和我的环境应该没啥问题吧…

感觉和环境真有关系,你确定一模一样?包括 time.sleep ?

对的 我一行代码都没改 直接 go build 运行的

在Go语言中,内存泄漏通常是由于不正确地管理内存(例如,未释放的动态内存分配)或者由于goroutine未正确同步或终止而导致的。针对你提到的“这段代码会内存泄漏吗?”的问题,由于你没有提供具体的代码片段,我将基于一些常见的情况来回答。

  1. 局部变量和内存管理:Go有垃圾回收机制(GC),会自动回收不再被引用的内存。因此,对于局部变量和通过newmake创建的局部对象,只要它们不再被引用,GC就会回收它们,通常不会导致内存泄漏。

  2. 全局变量和闭包:如果全局变量或闭包中的变量被无意中保留,并且不再需要,这可能导致内存无法被回收。确保这些变量在不再需要时被置为nil或重新赋值,有助于避免内存泄漏。

  3. goroutine管理:未正确管理的goroutine可能导致内存泄漏。例如,goroutine中启动了新的goroutine但没有适当的同步或终止机制,或者向已关闭的channel发送数据等,都可能导致资源无法释放。

  4. 第三方库:使用第三方库时,要确保它们正确管理内存。如果库内部存在内存泄漏,使用这些库的应用也可能会受到影响。

为了确切判断你的代码是否存在内存泄漏,建议分析具体的代码逻辑、内存使用情况以及goroutine的行为。同时,使用Go的内存分析工具(如pprof)可以帮助你识别和诊断潜在的内存泄漏问题。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!