为什么我的程序 运行 使用了这么多内存?
Why does my program run using so much memory?
我正在读一本关于 Erlang 的书,我从书中做了一个简单的例子。
%% exrs.erl
-module(exrs).
-export([sum/1]).
sum(0) -> 0;
sum(N) -> N + sum(N - 1).
当我运行此示例用于大数 (i.g.1000000000) 时,它在我的 PC 上使用 16Gb RAM 和 48Gb 交换文件来计算此函数。
1> exrs:sum(1000000000).
这是 Erlang VM 的常见行为吗?以及如何避免这样的问题?
PS:
10> erlang:system_info(version).
"11.1"
11> erlang:system_info(otp_release).
"23"
OS: Win10 x64
您的递归函数不能使用尾调用优化,因此它为每个递归调用使用堆栈帧。
1,000,000,000 次递归调用是很多堆栈帧。
例如,请参阅“了解一些 Erlang”的 this section 以了解更多详细信息。
如其他答案所述,您的递归未进行尾部优化。您的代码中发生的是 erlang 计算表达式的右侧并递归地将新函数调用附加到堆栈。喜欢下面
1_000_000 + sum(999_999 + sum(999_998 + sum(....)))
这就是吞噬你记忆的原因。正确的方法是编写接受累加器作为求和函数的第二个参数的函数,像这样
-module(exrs).
-export([sum/2]).
sum(0, ACC) -> ACC;
sum(N, ACC) -> sum(N - 1, ACC + N).
我正在读一本关于 Erlang 的书,我从书中做了一个简单的例子。
%% exrs.erl
-module(exrs).
-export([sum/1]).
sum(0) -> 0;
sum(N) -> N + sum(N - 1).
当我运行此示例用于大数 (i.g.1000000000) 时,它在我的 PC 上使用 16Gb RAM 和 48Gb 交换文件来计算此函数。
1> exrs:sum(1000000000).
这是 Erlang VM 的常见行为吗?以及如何避免这样的问题?
PS:
10> erlang:system_info(version).
"11.1"
11> erlang:system_info(otp_release).
"23"
OS: Win10 x64
您的递归函数不能使用尾调用优化,因此它为每个递归调用使用堆栈帧。
1,000,000,000 次递归调用是很多堆栈帧。
例如,请参阅“了解一些 Erlang”的 this section 以了解更多详细信息。
如其他答案所述,您的递归未进行尾部优化。您的代码中发生的是 erlang 计算表达式的右侧并递归地将新函数调用附加到堆栈。喜欢下面
1_000_000 + sum(999_999 + sum(999_998 + sum(....)))
这就是吞噬你记忆的原因。正确的方法是编写接受累加器作为求和函数的第二个参数的函数,像这样
-module(exrs).
-export([sum/2]).
sum(0, ACC) -> ACC;
sum(N, ACC) -> sum(N - 1, ACC + N).