【问题标题】:How to measure the performance of the Erlang Garbage Collector?如何衡量 Erlang 垃圾收集器的性能?
【发布时间】:2020-11-16 20:06:06
【问题描述】:

我最近开始使用 Erlang 进行编程,关于垃圾回收 (GC),我想了解一些事情。据我了解,每个进程的私有堆都有一个分代GC,全局共享堆有一个引用计数GC。

我想知道的是有没有办法得到:

  1. 收集周期数是多少?
  2. 在全局级别或进程级别分配和释放了多少字节?
  3. 什么是私有堆和共享堆大小?我们可以将其定义为 GC 参数吗?
  4. 收集垃圾需要多长时间?所需时间的百分比?
  5. 有没有办法在没有 GC 的情况下运行程序?

在我运行 Erlang 程序时,有没有办法通过代码或使用某些命令来获取此类信息?

谢谢。

【问题讨论】:

  • 我建议阅读 this blog post 并查看 recon library,两者均由 Fred Hébert 提供,也是 learn you some Erlang for great good! 的作者。
  • 理解你为什么问这个问题会很有趣。例如,您当前是否在您的 Erlang 应用程序中遇到 GC 问题,或者您是否在使用其他语言(如 Java)时遇到过令人失望的经历。请记住,Erlang GC 是针对 Erlang 进程的,而 GC 是针对 Java 的每个 JVM。这意味着行为完全不同。 Erlang 永远不会产生一次大的 GC。
  • “请记住,Erlang GC 是针对 Erlang 进程的,而 GC 是针对 Java 的 JVM”——我很清楚这一点,谢谢!我只是想了解 Erlang 的 GC 协议有多好。为此,我想尝试使用此类信息进行一些基准测试。顺便说一句,如果您知道有关 Erlang 的任何相关且有趣的基准测试,请告诉我。
  • 好佛朗哥。当越来越多的人意识到每个 JVM 的 GC 是一个真正的问题时,将会很有趣。即使使用像分代这样的“现代”GC,您通常也会每天左右完全停止一次,GC 会阻塞系统 10 到 100 秒。 GC 在堆大小方面不是线性过程这一事实尚未影响系统设计

标签: memory-management garbage-collection erlang


【解决方案1】:
  1. 要获取单个进程的信息,您可以致电erlang:process_info(Pid)。这将产生(从 Erlang 18.0 开始)以下字段:

    > erlang:process_info(self()).
    [{current_function,{erl_eval,do_apply,6}},
     {initial_call,{erlang,apply,2}},
     {status,running},
     {message_queue_len,0},
     {messages,[]},
     {links,[<0.27.0>]},
     {dictionary,[]},
     {trap_exit,false},
     {error_handler,error_handler},
     {priority,normal},
     {group_leader,<0.26.0>},
     {total_heap_size,4184},
     {heap_size,2586},
     {stack_size,24},
     {reductions,3707},
     {garbage_collection,[{min_bin_vheap_size,46422},
                          {min_heap_size,233},
                          {fullsweep_after,65535},
                          {minor_gcs,7}]},
     {suspending,[]}]
    

    进程的收集周期数可在garbage_collection 部分下的字段minor_gcs 中找到。

  2. 每个进程

    进程的当前堆大小可在上述结果的字段heap_size 中获得(换句话说,在 32 位 VM 上为 4 个字节,在 64 位 VM 上为 8 个字节)。进程的总内存消耗可以通过调用erlang:process_info(Pid, memory) 来获得,例如上述进程的{memory,34312}。这包括调用堆栈、堆和内部结构。

    可以使用erlang:trace/3 跟踪解除分配(和分配)。如果跟踪标志是garbage_collection,您将收到{trace, Pid, gc_start, Info}{trace, Pid, gc_end, Info} 形式的消息。 gc_start消息的Info字段包含heap_sizeold_heap_size等内容。

    每个系统

    系统顶层统计可以通过erlang:memory/0获取:

    > erlang:memory().
    [{total,15023008},
     {processes,4215272},
     {processes_used,4215048},
     {system,10807736},
     {atom,202481},
     {atom_used,187597},
     {binary,325816},
     {code,4575293},
     {ets,234816}]
    

    垃圾收集统计数据可以通过erlang:statistics(garbage_collection) 获得:

    > statistics(garbage_collection).
    {85,23961,0}
    

    其中(从 Erlang 18.0 开始)第一个字段是 VM 执行的垃圾回收的总数,第二个字段是回收的单词总数。

  3. 进程的堆大小可在上述进程信息中的字段total_heap_size(所有堆碎片和堆栈)和heap_size(最年轻的堆生成的大小)下获得。

    它们可以通过spawn options 控制,特别是min_heap_size,它设置进程的初始堆大小。

    要为所有进程设置它,可以调用erlang:system_flag(min_heap_size, MinHeapSize)

    您还可以通过 Erlang VM 的 +M... 选项控制全局 VM 内存分配。这些标志被描述为here。然而,这需要对 Erlang VM 及其分配器的内部有广泛的了解,并且不应掉以轻心。

  4. 这可以通过答案2中描述的跟踪获得。如果在跟踪时使用选项timestamp,您将收到每个跟踪消息的时间戳,可用于计算总GC时间。

  5. 简短回答:不。

    长答案:也许。您可以控制初始堆大小(通过min_heap_size),这将影响首次进行垃圾回收的时间。您还可以使用fullsweep_after 选项控制何时执行完整扫描。

更多信息可以在效率指南的Academic and Historical QuestionsProcesses 部分找到。

在运行时内省 Erlang 内存使用的最实用方法是通过Recon library,如Steve Vinoski mentioned

【讨论】:

    猜你喜欢
    • 2013-04-20
    • 2012-04-02
    • 2011-03-18
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    相关资源
    最近更新 更多