这是Julia 0.5中的一个简单函数。
function foo{T<:AbstractFloat}(x::T)
a = zero(T)
b = zero(T)
return x
end
我从julia --track-allocation=user
开始。然后include("test.jl")
。 test.jl只有这个功能。运行foo(5.)
。然后是Profile.clear_malloc_data()
。在REPL再次foo(5.)
。退出朱莉娅。查看文件test.jl.mem。
- function foo{T<:AbstractFloat}(x::T)
- a = zero(T)
194973 b = zero(T)
0 return x
- end
-
为什么这里分配了194973字节的内存?这也不是该功能的第一行。虽然在Profile.clear_malloc_data()
之后,这应该不重要。
答案 0 :(得分:8)
让我们澄清相关documentation的某些部分,这可能有点误导:
在解释结果时,有一些重要的细节。在用户设置下,由于REPL代码本身发生的事件,从REPL直接调用的任何函数的第一行都将显示分配。
实际上,分配的行是而不是的第一行。但是,它仍然是第一个跟踪线,因为Julia 0.5在实际的第一个语句上跟踪分配存在一些问题(在v0.6上已经fixed)。请注意,它也可能(与文档所说的相反)传播到函数中,即使它们使用@noinline
进行注释。唯一真正的解决方案是确保首先声明所调用的内容是您不想测量的内容。
更重要的是,JIT编译还增加了分配计数,因为Julia的大部分编译器都是用Julia编写的(并且编译通常需要内存分配)。建议的过程是通过执行要分析的所有命令强制编译,然后调用Profile.clear_malloc_data()来重置所有分配计数器。最后,执行所需的命令并退出Julia以触发生成.mem文件。
你是对的Profile.clear_malloc_data()
阻止计算JIT编译的分配。但是,本款与第一款分开;由于在REPL代码本身发生的&#34;事件,clear_malloc_data
对分配没有任何作用&#34;。
事实上,正如我确定您所怀疑的那样,此功能没有分配:
julia> function foo{T<:AbstractFloat}(x::T)
a = zero(T)
b = zero(T)
return x
end
foo (generic function with 1 method)
julia> @allocated foo(5.)
0
您看到的数字是由于REPL本身的事件造成的。要避免此问题,请将代码包装到函数中进行测量。也就是说,我们可以将此作为我们的测试工具,可能在使用foo
禁用@noinline
上的内联后。例如,这是修订后的test.jl
:
@noinline function foo{T<:AbstractFloat}(x::T)
a = zero(T)
b = zero(T)
return x
end
function do_measurements()
x = 0. # dummy statement
x += foo(5.)
x # prevent foo call being optimized out
# (it won't, but this is good practice)
end
然后是REPL会话:
julia> include("test.jl")
do_measurements (generic function with 1 method)
julia> do_measurements()
5.0
julia> Profile.clear_malloc_data()
julia> do_measurements()
5.0
产生预期结果:
- @noinline function foo{T<:AbstractFloat}(x::T)
0 a = zero(T)
0 b = zero(T)
0 return x
- end
-
- function do_measurements()
155351 x = 0. # dummy statement
0 x += foo(5.)
0 x # prevent foo call being optimized out
- # (it won't, but this is good practice)
- end
-