内存未释放回操作系统

时间:2019-02-23 17:41:32

标签: go vips

我创建了一个图像调整大小服务器,该服务器创建了一些不同的缩略图和您上传到其中的图像。我正在使用https://github.com/h2non/bimg软件包进行大小调整,该软件包正在使用带有c绑定的libvips。

在投入生产之前,我已经开始使用jmeter对我的应用程序进行压力测试,并相继几次将100张图像同时上传到它,并注意到内存并未释放回操作系统。

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

我的代码和内存/ CPU图可以在这里找到: https://github.com/hamochi/bimg-memory-issue

很明显,内存在每个周期都可以重复使用,否则应该增加一倍(我认为)。但是它从未发布回操作系统。

这是cgo的普遍行为吗?或bimg所做的事情很奇怪。还是仅仅是我的代码有问题?

非常感谢您能提供的任何帮助!

2 个答案:

答案 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))