Erlang翻译崩溃

Jen*_*nov 1 erlang

我有一个小程序,读取一个csv文件(100M).问题是我的程序使Erlang解释器崩溃:

Crash dump was written to: erl_crash.dump
eheap_alloc: Cannot reallocate 3563526520 bytes of memory (of type "heap").
Aborted
Run Code Online (Sandbox Code Playgroud)

这是程序:

readlines(FileName) ->
    {ok, Device} = file:open(FileName, [read]),
    try get_all_lines(Device)
      after file:close(Device)
    end.


get_all_lines(Device) ->
    case io:get_line(Device, "") of
        eof -> [];
        Line -> [Line | get_all_lines(Device)]
    end.
Run Code Online (Sandbox Code Playgroud)

我这样做:

Path="...csv".
Lines=tut6:readlines(Path).
Run Code Online (Sandbox Code Playgroud)

这会导致崩溃.

有人可以告诉我这是什么问题吗?也许我的程序有问题?我怎样才能避免崩溃?

提前致谢

Gre*_*reg 5

您是否意识到3563526520是3.3 GB?你的系统有多少内存?巨大的内存消耗源于您选择了最优的算法来读取行:

  1. 在尝试操作之前,您尝试读取内存中的所有行
  2. 您选择将文本表示为列表,对于从文件读取的每个字符使用8个字节(或64位系统上的16个字节)
  3. 您不使用尾递归,这意味着编译器无法优化您的代码以提高内存效率

所以,要修复代码:

  1. 一次读取一行,然后解析并处理它并存储为Erlang术语而不是原始输入数据
  2. 根据Hynek -Pichi- Vychodil的建议,将行读作二进制文件
  3. 使函数读取文件尾递归

了解一些如果你想知道如何正确实现这些函数,Erlang对尾递归函数有很好的讨论.

如果函数是以尾递归的方式编写的,那么整个算法可能如下所示:

get_all_lines(Device) ->
    get_all_lines(Device, []).

get_all_lines(Device, List) ->
    case io:get_line(Device, "") of
        eof ->
            lists:reverse(List);
        Line ->
            Data = process_line(Line),
            get_all_lines(Device, [Data | List])
    end.
Run Code Online (Sandbox Code Playgroud)