原文: http://numba.pydata.org/numba-doc/latest/developer/live_variable_analysis.html
(相关问题 numba/numba#1611 )
Numba 使用引用计数进行垃圾收集,这是一种需要编译器协作的技术。 Numba IR 编码必须插入减量的位置。这些位置由实时变量分析确定。相应的源代码是 https://github.com/numba/numba/blob/master/numba/interpreter.py 中的_insert_var_dels()
方法。
在 Python 语义中,一旦在函数内定义了变量,它就会一直存活,直到明确删除变量或结束函数作用域。但是,Numba 分析代码以通过其定义和编译期间的用法来确定每个变量的生命周期的最小界限。一旦变量无法访问,就会在最近的基本块(在下一个块的开头或当前块的末尾)插入del
指令。这意味着变量可以比常规 Python 代码更早发布。
实时变量分析的行为会影响已编译代码的内存使用情况。在内部,Numba 不区分临时变量和用户变量。由于每个操作都生成至少一个临时变量,因此如果不尽快释放,则函数可以累积大量临时变量。我们的生成器实现可以从早期释放变量中受益,这减少了在每个屈服点处暂停的状态的大小。
(相关问题: numba/numba#1738 )
当变量生命周期被限制在循环体内时(它的定义和用法不会逃脱循环体),如:
def f(arr):
# BB 0
res = 0
# BB 1
for i in (0, 1):
# BB 2
t = arr[i]
if t[i] > 1:
# BB 3
res += t[i]
# BB 4
return res
变量t
永远不会在循环外引用。在定义变量之前,在循环开头(BB 1)为t
发出del
指令。一旦我们知道控制流图,原因很明显:
+------------------------------> BB4
|
|
BB 0 --> BB 1 --> BB 2 ---> BB 3
^ | |
| V V
+---------------------+
变量t
在 BB 1 中定义。在 BB 2 中,t[i] > 1
的评估使用t
,如果执行采用假分支并转到 BB 1,则最后一次使用。在 BB 3 中,t
仅为在res += t[i]
中使用,如果执行采用 true 分支,这是最后一次使用。因为 BB 3,BB 2 的传出分支使用t
,所以必须在共同的前任中删除t
。最近的点是 BB 1,它没有从 BB 0 的入射边缘定义t
。
或者,如果在 BB 4 处删除t
,我们仍然必须在其定义之前删除变量,因为可以在不执行定义变量的循环体(BB 2 和 BB 3)的情况下执行 BB4。