我创建了一个图像调整大小服务器,该服务器创建了一些不同的缩略图和您上传到其中的图像。我正在使用https://github.com/h2non/bimg软件包进行大小调整,该软件包正在使用带有c绑定的libvips。
在投入生产之前,我已经开始使用jmeter对我的应用程序进行压力测试,并相继几次将100张图像同时上传到它,并注意到内存并未释放回操作系统。
为了说明这个问题,我写了几行代码,读取100张图像并调整它们的大小(不保存它们的位置),然后等待10分钟。这样重复5次
我的代码和内存/ CPU图可以在这里找到: https://github.com/hamochi/bimg-memory-issue
很明显,内存在每个周期都可以重复使用,否则应该增加一倍(我认为)。但是它从未发布回操作系统。
这是cgo的普遍行为吗?或bimg所做的事情很奇怪。还是仅仅是我的代码有问题?
非常感谢您能提供的任何帮助!
答案 0 :(得分:1)
有一个libvips可以跟踪和调试引用计数-您可以尝试启用它并查看是否有泄漏。
https://libvips.github.io/libvips/API/current/libvips-vips.html#vips-leak-set
尽管您在上面有关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进程只能在堆末尾将页面释放回OS(请看brk和sbrk sys调用):
https://en.wikipedia.org/wiki/Sbrk
现在想象一下,如果1)libvips分配了6GB,2)Go运行时分配了100kb,3)libvips释放了6GB。您的libc(在您的进程中将代表您分别调用sbrk和brk的东西)由于堆末尾有100kb的分配,因此无法将6GB交还给操作系统。一些malloc实现具有比其他实现更好的内存碎片行为,但是默认的Linux实现非常好。
实际上,没关系。 malloc将重用您的内存空间中的漏洞,即使不这样做,它们也将在内存压力下被分页,并且最终不会占用RAM。尝试运行您的流程几个小时,然后观看RES。您应该看到它爬上来,然后稳定下来。
(我根本不是一个有内核的人,以上只是我的理解,当然很欢迎更正)
答案 1 :(得分:0)
问题出在调整大小代码中:
_, err = bimg.NewImage(buffer).Resize(width, height)
该图像是gobject,需要显式取消引用才能释放内存,请尝试:
image, err = bimg.NewImage(buffer).Resize(width, height)
defer C.g_object_unref(C.gpointer(image))