我一直在使用Julia对大量数据进行多线程处理,并观察到一种交错模式。内存使用量(由htop
报告)缓慢增长,直到该进程被OS终止。该项目很复杂,很难产生合适的MWE,但是我进行了一个简单的实验:
using Base.Threads
f(n) = Threads.@threads for i=1:n
x = zeros(n)
end
现在,我反复调用f(n)
以获得n的各种值(在我的64 Gb计算机上介于10 ^ 4和10 ^ 5之间)。结果是,有时一切都按预期工作,并且返回后释放内存,但是有时情况并非如此,htop
报告的已用内存量即使看起来似乎没有进行任何计算,也都挂在一个很大的值上:
显式垃圾回收GC.gc()
只能帮助一点点,释放一些内存,但是只有一小块。同样,有时在函数GC.gc()
中的循环中调用f
会有所帮助,但是问题仍然存在,并且当然会降低性能。退出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
答案 0 :(得分:0)
自从很久以前就有人问过这个问题,希望这不再发生——尽管我无法在没有 MWE 的情况下进行测试。
然而,值得注意的一点是 Julia 垃圾收集器是单线程的;即,无论您有多少线程生成垃圾,都只有一个垃圾收集器。
因此,如果您要在并行工作流中生成大量垃圾,通常建议使用多处理(即 MPI.jl 或 Distributed.jl)而不是多线程。在多处理中,与多线程相比,每个进程都有自己的 GC。