我一直在使用Julia进行大量数据的多线程处理,并观察到一个有趣的模式。内存使用情况(由htop
报告)会慢慢增长,直到进程被操作系统杀死。该项目很复杂,很难生成一个合适的最小工作示例,但我进行了简单的实验:
using Base.Threads
f(n) = Threads.@threads for i=1:n
x = zeros(n)
end
现在,我在我的64 Gb机器上为各种值的n(在10^4和10^5之间)重复调用f(n)
。结果是有时一切都按预期工作,内存在返回后被释放,但有时情况并非如此,并且由htop
报告的已使用内存数量停留在一个很大的值,即使似乎没有进行计算:
显式垃圾回收GC.gc()
只有少量内存被释放。同时,在函数f
中的循环中有时调用GC.gc()
有所帮助,但问题仍然存在,并且当然会降低性能。退出Julia后,分配的内存恢复正常(可能由OS释放)。我读过关于julia如何管理其内存以及只有当内存合计比某个值更大时才释放内存的文章。但在我的情况下,它导致进程被OS杀死。对我来说,GC似乎以某种方式失去了对所有分配的内存的跟踪。
请问有谁可以解释这种行为以及如何在不通过重复调用
GC.gc()
减慢代码的情况下防止它发生?为什么垃圾回收会以这种方式失效?更多细节:
- 只有在多个线程中处理大数据(分配大量内存)时才会发生这种情况。我无法通过只使用一个线程来重现相同的问题。 - 我检查了我的代码,排除了我所知道的所有可能导致增加内存消耗的因素(全局变量、类型稳定性等),但没有积极的结果。据我所知,这些问题会导致内存分配更高,而我这里的问题是函数返回后内存没有被释放。 - 这是我的
versioninfo
输出:julia> versioninfo()
Julia Version 0.7.0
Commit a4cb80f3ed (2018-08-08 06:46 UTC)
Platform Info:
OS: Linux (x86_64-pc-linux-gnu)
CPU: Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-6.0.0 (ORCJIT, skylake)
Environment:
JULIA_NUM_THREADS = 36