去GC似乎没有收集我的未引用的图像加载指针? [关闭]

问题描述 投票:-2回答:1

我正在Go中使用OpenGL开发一个项目,并且有代码通过go / image库加载图像文件。这个函数没有留下永久指针,然后我留下了函数的范围。我希望这个内存在下一个GC循环中被清除,但它似乎没有。我希望有一个了解得更好的人可以帮助我了解为什么图像没有被清除。

代码的要点:https://gist.github.com/gjh33/62a75ccde6a7d849311804d31d7ee9ff

不调用此方法时,内存占用量为17mb,调用此方法时为40mb。在等待5分钟之后,这个内存GC绝对没有了。

如果你还没有使用openGL,请记住一些事情:

  • 与不安全指针(第41行)的对话通过以下方式发生:qazxsw poi
  • 我正在使用go-gl v3.2-core
  • 如果您需要更多信息或背景,请询问
image go garbage-collection
1个回答
4
投票

当我离开函数的范围时,我希望这个内存被清除

这是一个主要的误解:Go是一种垃圾收集语言,这意味着内存只在所谓的垃圾收集过程中被释放,垃圾收集会定期发生,并且不会被正在执行的代码中的变量触发超出范围。

可以说,在GC算法Go实现中,每个扫描包括两个连续阶段:扫描和扫描。在扫描阶段,遍历所有活动对象(通过它们彼此保持的指针,如果有的话),并且通过运行的goroutine和全局变量的堆栈无法访问的指针被标记为在扫描阶段期间发生的释放。

Go运行时实现了一个非常复杂的“估计器”,它试图推断出哪个目标堆大小开始下一个GC会话,以便在堆使用和执行GC会话所支付的CPU成本之间取得平衡。

这意味着两件事:

  • 在Go中,您丢失了对一块已分配内存的所有引用这一事实对运行时没有任何意义:这个事实只会在下一个GC周期中考虑。
  • 在不执行分配的空闲程序中,一块分配的存储器有可能根本不被收集 - 因为不会执行GC循环。

另一方面,你所持有的GC工作方式的原始心理图像本身并不是不真实的 - 确实存在没有显式内存管理的编程语言,它实际上在你提到的情况下解除了内存的分配。这通常用于编写脚本(至少是最初的)编程语言,例如Python,Tcl,Perl(至少≤5)等。这些语言对它们操作的值使用所谓的引用计数。逻辑基本上是每个赋值给变量(包括将它作为函数的参数传递)增加了为该变量记录的一些引用,并且当执行离开变量的范围时,值的refcount保存在它递减了。当值的引用计数降为0时,将释放该值。

这种方法很有效,看起来很自然,但它有一些缺点,例如:

  • 需要为每个值维护refcount字段。
  • 每次必须更新该字段时都需要花费CPU周期(再加上CPU缓存抖动)。
  • 该方案无法处理循环引用。

我还要补充一点,这个方案在并发访问变量方面效果不佳:如果你在混合中添加并发(如在Go中),你最终会要求这些引用计数字段的所有更新都是相互排斥和不完整的问题,例如如何处理一个执行线程未引用值的情况,注意到refcount越过零并释放值,然后另一个等待前者增加引用的线程被解除阻塞并查找它想要引用的值不再存在。

© www.soinside.com 2019 - 2024. All rights reserved.