Go 内存未释放回操作系统

Go 内存未释放回操作系统,go,vips,Go,Vips,我已经创建了一个图像大小调整服务器,它可以创建一些不同的缩略图,并上传到其中。我使用这个包来调整大小,它使用带有c绑定的libvips 在投入生产之前,我已经开始使用jmeter对我的应用程序进行压力测试,并在每次测试之后将100个图像同时上传到应用程序中,并且注意到内存没有被释放回操作系统 为了说明这个问题,我编写了几行代码,读取100个图像并调整它们的大小(不将它们保存在任何地方),然后等待10分钟。这样重复5次 我的代码和内存/CPU图可以在这里找到: 很明显,内存一直在重复使用,否则它

我已经创建了一个图像大小调整服务器,它可以创建一些不同的缩略图,并上传到其中。我使用这个包来调整大小,它使用带有c绑定的libvips

在投入生产之前,我已经开始使用jmeter对我的应用程序进行压力测试,并在每次测试之后将100个图像同时上传到应用程序中,并且注意到内存没有被释放回操作系统

为了说明这个问题,我编写了几行代码,读取100个图像并调整它们的大小(不将它们保存在任何地方),然后等待10分钟。这样重复5次

我的代码和内存/CPU图可以在这里找到:

很明显,内存一直在重复使用,否则它应该加倍(我认为)。但它从未发布回操作系统

这是cgo的一般行为吗?或者bimg在做一些奇怪的事情。还是只是我的代码有问题


非常感谢您能给予的任何帮助

有一个libvips工具可以跟踪和调试引用计数——您可以尝试启用它,看看是否有泄漏

尽管从你上面关于bimg内存统计的评论来看,听起来似乎一切都还可以

从Python测试libvips内存很容易。我制作了一个小程序:

#!/usr/bin/python3

import pyvips
import sys

# disable libvips operation caching ... without this, it'll cache all the
# thumbnail operations and we'll just be testing the jpg write
pyvips.cache_set_max(0)

for i in range(0, 10000):
    print("loop {} ...".format(i))
    for filename in sys.argv[1:]:
        # thumbnail to fit 128x128 box
        image = pyvips.Image.thumbnail(filename, 128)
        thumb = image.write_to_buffer(".jpg")
重复缩略一组源图像。我是这样运行的:

$ for i in {1..100}; do cp ~/pics/k2.jpg $i.jpg; done
$ ../fing.py *
并在顶部观看了RES。我看到:

loop | RES (kb)
  -- | --
 100 | 39220
 250 | 39324
 300 | 39276
 400 | 39316
 500 | 39396
 600 | 39464
 700 | 39404
1000 | 39420
只要您没有refcount泄漏,我认为您看到的是预期的行为。Linux进程只能将堆末尾的页面释放回操作系统(请查看brk和sbrk sys调用):

现在想象一下,如果1)libvips分配6GB,2)Go运行时分配100kb,3)libvips释放6GB。您的libc(进程中代表您调用sbrk和brk的东西)无法将6GB的内存交回操作系统,因为堆末尾有100kb的alloc。一些malloc实现比其他实现具有更好的内存碎片行为,但是默认的linux实现相当不错

实际上,这并不重要。malloc将重用内存空间中的漏洞,即使它没有,它们也会在内存压力下被调出,最终不会占用内存。试着运行你的进程几个小时,然后观察RES。你应该看到它慢慢上升,然后稳定下来


(我根本不是一个内核人,以上只是我的理解,当然非常欢迎更正)

问题在于调整代码的大小:

_, err = bimg.NewImage(buffer).Resize(width, height)
图像是gobject,需要显式取消刷新以释放内存,请尝试:

image, err = bimg.NewImage(buffer).Resize(width, height)
defer C.g_object_unref(C.gpointer(image))

你确定是Go程序使用了内存吗?例如,这种用法是否包括文件系统缓存?你知道这是怎么测量的吗?top显示了什么?是的,我也在用top进行测量,正如我们所说的,根据top,这个过程仍然使用38.2%。当我用docker统计数据监视它并在容器中运行它时,情况也是如此。我在我的回购协议中添加了top的截图。相关的,这解释了吗?我以前读过这篇文章,并决定将bimg改为一个纯粹的图像大小调整库(这比libvips更需要内存)。正如帖子所解释的,内存最终被释放回操作系统,我也可以使用debug.FreeOSMemory()强制执行。bimg的情况并非如此,因此我问这是否是一般的cgo行为。cgo行为与C相同。您是否尝试释放VIP使用的缓存?非常感谢您的解释。我将运行我的进程几个小时,看看它是如何进行的。我希望它能将内存释放回操作系统,因为这将帮助我更容易地扩展upp服务,但我有其他方法可以解决这个问题。与其他库相比,Libvips的速度和内存效率仍然高得离谱,我会坚持使用它。我的进程运行了17个小时,时间更长。第一次内存增加,直到崩溃。第二次它更稳定时,它增加到78%,一直在那里,直到它停止调整大小(17小时后),并下降到65%左右。它似乎足够稳定,我只需要确保它重新启动,以防再次崩溃。我添加了一个py程序来显示libvips memuse。我在这里看到一个稳定的40mb左右。