try*_*lve 4 memory memory-management julia
我有一个嵌套的循环迭代方案,占用了大量的内存.我确实理解我不应该使用全局变量,但即使我将所有内容都包含在函数中,内存情况也没有改善.它只是在每次迭代后累积,就像没有垃圾收集一样.
这是一个可行的例子,类似于我的代码.
我有两个文件.首先,functions.jl:
##functions.jl
module functions
function getMatrix(A)
L = rand(A,A);
return L;
end
function loopOne(A, B)
res = 0;
for i = 1:B
res = inv(getMatrix(A));
end
return(res);
end
end
Run Code Online (Sandbox Code Playgroud)
第二档main.jl:
##main.jl
include("functions.jl")
function main(C)
res = 0;
A = 50;
B = 30;
for i =1:C
mat = functions.loopOne(A,B);
res = mat .+ 1;
end
return res;
end
main(100)
Run Code Online (Sandbox Code Playgroud)
当我执行时julia main.jl,内存随着我的扩展C而增加main(C)(当我增加到C1000000 时,有时会增加到数百万个分配和10GiB ).
我知道这个例子看起来没用,但它类似于我的结构.有人可以帮忙吗?谢谢.
更新:
Michael K. Borregaard给出了一个非常有帮助的答案:
module Functions #1
function loopOne!(res, mymatrix, B) #2
for i = 1:B
res .= inv(rand!(mymatrix)) #3
end
return res #4
end
end
function some_descriptive_name(C) #5
A, B = 50, 30 #6
res, mymat = zeros(A,A), zeros(A,A)
for i =1:C
res .= Functions.loopOne!(res, mymat, B) .+ 1
end
return res
Run Code Online (Sandbox Code Playgroud)
但是,当我计时时,拨号和内存仍会随着拨号而增加C.
@time some_descriptive_name(30)
0.057177 seconds (11.77 k allocations: 58.278 MiB, 9.58% gc time)
@time some_descriptive_name(60)
0.113808 seconds (23.53 k allocations: 116.518 MiB, 9.63% gc time)
Run Code Online (Sandbox Code Playgroud)
我相信这个问题来自于这个inv功能.如果我将代码更改为:
function some_descriptive_name(C) #5
A, B = 50, 30 #6
res, mymat = zeros(A,A), zeros(A,A)
for i =1:C
res .= res .+ 1
end
return res
end
Run Code Online (Sandbox Code Playgroud)
然后内存和分配将保持不变:
@time some_descriptive_name(3)
0.000007 seconds (8 allocations: 39.438 KiB)
@time some_descriptive_name(60)
0.000037 seconds (8 allocations: 39.438 KiB)
Run Code Online (Sandbox Code Playgroud)
有没有办法在使用后"清除"内存inv?由于我没有创建任何新内容或存储任何新内容,因此内存使用量应保持不变.
Mic*_*ard 11
至少有几点建议:
getMatrix函数每次都分配一个新的AxA矩阵.这肯定会消耗内存.如果可以,最好避免分配,例如通过使用rand!随机值填充现有数组.
该res = 0行定义res为a,Int但随后您将其分配Matrix{Float}给它(结果inv(getMatrix)).更改代码中变量的类型使编译器很难弄清楚类型是什么,这会导致代码变慢.
看来你有一个名为的模块,functions但是你没有写它.
该res = inv代码行不断改写值,因此该循环什么也不做!
结构和代码看起来像C++.试着看风格指南.
以下是代码以更加思想的方式看起来如何避免分配:
module Functions #1
function loopOne!(res, mymatrix, B) #2
for i = 1:B
res .= inv(rand!(mymatrix)) #3
end
return res #4
end
end
function some_descriptive_name(C) #5
A, B = 50, 30 #6
res, mymat = zeros(A,A), zeros(A,A)
for i =1:C
res .= Functions.loopOne!(res, mymat, B) .+ 1
end
return res
end
Run Code Online (Sandbox Code Playgroud)
评论:
如果您愿意,可以使用模块 - 由您决定是否将内容放在不同的文件中.模块名称大写.
如果可以,使用覆盖现有容器值的函数是有利的.这些函数最终!表示它们将修改参数(比如通过引用可变地传递,而不是在C++中使它成为const).
使用.=运算符表示您没有创建新容器,而是覆盖现有容器的元素.该rand!功能会被覆盖mymatrix.
不严格需要return关键字,但DNF建议在评论中使用更好的样式
该main约定未在Julia中使用,因为大多数代码由用户调用,而不是由程序执行.
多个变量的紧凑分配格式.
请注意,在这种情况下,这些优化都不重要,因为99%的计算时间花费在昂贵的inv功能上.
对更新的反应:inv函数没有任何问题,它只是一个昂贵的操作.但我想你可能会误解记忆计数的作用.并不是说内存使用量正在增加,就像你在C++中寻找的那样,如果你有一个指向永不释放的对象的指针(内存泄漏).内存使用是不变的,但分配的总和会增加,因为inv函数必须进行一些内部分配.
考虑这个例子
for i in 1:n
b = [1, 2, 3, 4] # Here a length-4 Array{Int64} is initialized in memory, cost is 32 bytes
end # Here, that memory is released.
Run Code Online (Sandbox Code Playgroud)
对于每次通过for循环的运行,分配32个字节,并释放32个字节.当循环结束时,无论n如何,都将从该操作分配0个字节.但是Julia的内存跟踪只会增加分配 - 所以在运行代码后你会看到32*n字节的分配.julia这样做的原因是在RAM中分配空间是计算中最昂贵的操作之一 - 因此减少分配是加速代码的好方法.但你无法避免它.
因此,您的代码没有任何问题(以新格式) - 您看到的内存分配和时间只是执行大(昂贵)操作的结果.
| 归档时间: |
|
| 查看次数: |
599 次 |
| 最近记录: |