memory-leaks - 需要帮助修复 elixir 和 sweet_xml 库的内存泄漏

标签 memory-leaks elixir openstreetmap

我是 Elixir 的新手。

我有以下 lib/osm.ex文件

defmodule Osm do
  import SweetXml

  def hello do
    :world
  end

  def main(args) do
    args |> parse_args |> process
  end

  defp parse_args(args) do
    {options, _, _} = OptionParser.parse(args, switches: [osm_file: :string, help: :boolean])
    options
  end

  def output_help() do
    IO.puts "Usage: osm [OPTION]"
    IO.puts ""
    IO.puts "  --osm-file  an osm-file to import"
    IO.puts "  --help      outputs this help-page"
  end

  def process([]) do
    IO.puts "No arguments given"
  end

  def process(options) do
    if options[:help] do
      output_help()
    else
      case options do
        [osm_file: _] ->
          process_osm_file(options[:osm_file])
      end
    end
  end

  def process_osm_file(file) do
    counts = %{:nodes => 0, :ways => 0, :relations => 0}
    cond do
      String.ends_with?(file, ".pbf") ->
        IO.puts "parse osm-pbf."
      String.ends_with?(file, ".osm.bz2") ->
        IO.puts "extract and parse osm-xml."
      String.ends_with?(file, ".osm") ->
        IO.puts "parse osm-xml."
        File.stream!(file)
         |> stream_tags([:node, :way, :relation], discard: [:node, :way, :relation])
          |> Stream.map(fn
            {_, node} ->
              process_element(node, counts)
          end)
          |> Enum.reduce(fn element, result ->
            result_modified = %{result |
              nodes: result[:nodes] + element[:nodes],
              ways: result[:ways] + element[:ways],
              relations: result[:relations] + element[:relations]
            }
            cond do
              rem(result_modified[:nodes], 1000) == 0 ->
                IO.write "\rnodes: " <> to_string(result_modified[:nodes]) <> "; ways: " <> to_string(result_modified[:ways]) <> "; relations: " <> to_string(result_modified[:relations]) <> "; mem: " <> to_string(:erlang.memory(:total))
              true -> true
            end
            result_modified
          end)
          |> Stream.run
          IO.puts ""
      true ->
        IO.puts "invalid osm-file extension."
    end
  end

  defp process_element(doc, counts) do
    case doc |> xmlElement(:name) do
      :node ->
        doc |> xmap(
          id: ~x"./@id"i,
          lat: ~x"./@lat"f,
          lon: ~x"./@lon"f,
          tags: [
            ~x"./tag"l,
            key: ~x"./@k"s,
            value: ~x"./@v"s
          ]
        ) |> process_node(counts)

      :way ->
        doc |> xmap(
          id: ~x"./@id"i,
          nd: [
            ~x"./nd"l,
            ref: ~x"./@ref"i
          ],
          tags: [
            ~x"./tag"l,
            key: ~x"./@k"s,
            value: ~x"./@v"s
          ]
        ) |> process_way(counts)

      :relation ->
        doc |> xmap(
          id: ~x"./@id"i,
          member: [
            ~x"./member"l,
            type: ~x"./@type"s,
            ref: ~x"./@ref"s,
            role: ~x"./@role"s
          ],
          tags: [
            ~x"./tag"l,
            key: ~x"./@k"s,
            value: ~x"./@v"s
          ]
        ) |> process_relation(counts)

      _ ->
        IO.puts "unhandled element"
    end
  end

  defp process_node(node, counts) do
    _ = node
    Map.put(counts, :nodes, counts[:nodes] + 1)
  end

  defp process_way(way, counts) do
    _ = way
    Map.put(counts, :ways, counts[:ways] + 1)
  end

  defp process_relation(relation, counts) do
    _ = relation
    Map.put(counts, :relations, counts[:relations] + 1)
  end
end

以及以下 mix.exs文件
defmodule Osm.MixProject do
  use Mix.Project

  def project do
    [
      app: :osm,
      version: "0.1.0",
      elixir: "~> 1.7",
      start_permanent: Mix.env() == :prod,
      escript: [main_module: Osm],
      deps: deps()
    ]
  end

  def application do
    [
      extra_applications: [:logger]
    ]
  end

  defp deps do
    [
      {:sweet_xml, github: 'kbrw/sweet_xml', app: false}
    ]
  end
end

我用 mix escript.build 编译它

我已经下载了 berlin-latest.osm.bz2 file并提取了 berlin-latest.osm 文件。

如果我打电话./osm --osm-file=berlin-latest.osm
该脚本解析 xml-data 并正确计算节点、方式和关系,但内存消耗一直增加到最后。

SweetXml 库中是否存在内存泄漏,或者我做错了什么?

最佳答案

我没有看到会在您的代码中造成内存泄漏的内容。

我做了以下测试:我使用 SweetXml 逐步删除了所有代码,并且当我使用 SweetXml 撤回第一部分(即: stream_tags([:node, :way, :relation], discard: [:node, :way, :relation]) )时,内存泄漏消失了。 这清楚地表明内存消耗来自 SweetXml

阅读 SweetXml.stream_tags/3 的源码函数,或许能给你带来一些答案。我还没有弄明白泄漏是从哪里来的。

编辑:在彻底检查源代码后,我仍然没有找到泄漏的来源。我开始认为它更深层次的东西,可能与 erlang VM 的工作方式有关。

关于memory-leaks - 需要帮助修复 elixir 和 sweet_xml 库的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52283311/

相关文章:

python - BeautifulSoup 寻找 xml 标签

java - 如何在 JMapViewer 中表示路由

memory-leaks - 根据优化级别导致内存泄漏的延迟长度字符变量

ios - 对象实例可以释放自己吗?

javascript - react 组件状态内存泄漏

https - 向同一主机但不同主机 ip 发送 HTTPS get 请求

for-loop - Elixir 用for循环填充列表

haskell - Haskell 和流融合不断增加 CPU 消耗

ruby-on-rails - 在 Web 应用程序中使用哪些框架/技术来实现实时功能?

r - 在 R 中使用 Open Street Map 和 get_osm {osmar}