Go GC似乎没有收集我未引用的图像加载指针?

时间:2018-09-01 14:16:17

标签: image go garbage-collection

我正在使用OpenGL在Go中的项目中工作,并且具有通过go / image库加载图像文件的代码。这个函数没有留下永久的指针,然后我离开了函数的范围。我希望此内存在下一个GC周期中被清除,但事实并非如此。我希望能有所了解的人能帮助我了解为什么无法清除图像。

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

不调用此方法时,内存占用为17mb,而调用此方法时为40mb。即使等待了5分钟,此内存GC也绝不会消失。

如果您没有在goGL中使用过openGL,请记住以下几点:

1 个答案:

答案 0 :(得分:4)

  

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

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

足以说明Go算法所执行的GC算法中,每次扫描都包含两个连续的阶段:扫描和扫描。 在扫描阶段,遍历所有活动对象(通过它们相互维护的指针,如果有的话,并且通过运行的goroutine和全局变量的堆栈无法访问的对象被标记为释放,这在扫描阶段发生。< / p>

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

这意味着两件事:

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

在旁注中,GC的原始心理意象 您所拥有的作品本身并不是真正的错误-确实存在不具有显式内存管理的编程语言,这些语言实际上会在您提到的情况下实际取消分配内存。这是脚本(至少最初是)脚本语言(例如Python,Tcl,Perl(至少≤5)等)的典型用法。这些语言对它们使用的 values 使用所谓的引用计数。逻辑基本上是,对变量的每个值赋值(包括将其作为函数的参数传递)都会增加该变量记录的引用数量,并且当执行离开变量的范围时,该值的引用计数将保留在其中。它递减。当值的引用计数降至0时,该值被释放。

这种方法行之有效,而且看起来很自然,但是它具有某些缺点,例如:

  • 需要为每个值维护一个引用计数字段。
  • 每次必须更新该字段时都需要花费CPU周期(这还增加了CPU缓存的崩溃)。
  • 该方案无法处理循环引用。

我还要补充一点,该方案在并发访问变量时不能很好地发挥作用:如果在混合中添加并发(如Go中一样),最终将需要对这些引用计数进行所有更新字段是互斥的,并且会出现一些有趣的问题,例如如何处理一个执行线程取消引用某个值,注意到refcount越过零并释放该值,然后另一个线程等待前者增加引用的情况畅通无阻,找出要引用的值不再存在。