当前位置: 首页 > 面试题库 >

Erlang及其对堆内存的消耗

何雅惠
2023-03-14
问题内容

我在HP
Proliant服务器上运行了高度并发的应用程序。该应用程序是我用erlang编码的文件系统索引器。它在文件系统上找到的每个文件夹中产生一个进程,并将所有文件路径记录在碎片化的Mnesia数据库中。(数据库由disc_only_copies表的类型组成,其文件系统的屏幕快照可在
此处 查看。)

下面显示了完成文件系统的高强度工作的代码片段:


%%% -------- COPYRIGHT NOTICE --------------------------------------------------------------------
%% @author Muzaaya Joshua, <joshmuza@gmail.com> [http://joshanderlang.blogspot.com]
%% @version 1.0 free software, but modification prohibited
%% @copyright Muzaaya Joshua (file_scavenger-1.0) 2011 - 2012 . All rights reserved
%% @reference <a href="http://www.erlang.org">OpenSource Erlang WebSite</a>
%% 
%%% ---------------- EDOC INTRODUCTION TO THE MODULE ----------------------------------------------
%% @doc This module provides the low level APIs for reading, writing,
%% searching, joining and moving within directories.The module implementation
%% took place on @date at @time.
%% @end

-module(file_scavenger_utilities).

%%% ------- EXPORTS -------------------------------------------------------------------------------
-compile(export_all).

%%% ------- INCLUDES -----------------------------------------------------------------------------

%%% -------- MACROS ------------------------------------------------------------------------------
-define(IS_FOLDER(X),filelib:is_dir(X)).
-define(IS_FILE(X),filelib:is_file(X)).
-define(FAILED_TO_LIST_DIR(X),error_logger:error_report(["*** File Scavenger Utilities Error ***** ",{error,"Failed to List Directory"},{directory,X}])).
-define(NOT_DIR(X),error_logger:error_report(["*** File Scavenger Utilities Error ***** ",{error,"Not a Directory"},{alleged,X}])).
-define(NOT_FILE(X),error_logger:error_report(["*** File Scavenger Utilities Error ***** ",{error,"Not a File"},{alleged,X}])).
%%%--------- TYPES -------------------------------------------------------------------------------

%% @type dir() = string(). 
%%  Must be containing forward slashes, not back slashes. Must not end with a slash
%%  after the exact directory.e.g this is wrong: "C:/Program Files/SomeDirectory/"
%%  but this is right: "C:/Program Files/SomeDirectory"
%% @type file_path() = string(). 
%%  Must be containing forward slashes, not back slashes.
%%  Should include the file extension as well e.g "C:/Program Files/SomeFile.pdf"

%% -----------------------------------------------------------------------------------------------
%% @doc Enters a directory and executes the fun ForEachFileFound/2 for each file it finds
%% If it finds a directory, it executes the fun %% ForEachDirFound/2. 
%% Both funs above take the parent Dir as the first Argument. Then, it will spawn an 
%% erlang process that will spread the found Directory too in the same way as the parent directory 
%% was spread. The process of spreading goes on and on until every File (wether its in a nested 
%% Directory) is registered by its full path.
%% @end
%%
%% @spec spread_directory(dir(),dir(),funtion(),function())-> ok.

spread_directory(Dir,Top_Directory,ForEachFileFound,ForEachDirFound) when is_function(ForEachFileFound),is_function(ForEachDirFound) ->
    case ?IS_FOLDER(Dir) of
        false -> ?NOT_DIR(Dir); 
        true -> 
            F = fun(X)->
                    FileOrDir = filename:absname_join(Dir,X),
                    case ?IS_FOLDER(FileOrDir) of
                        true -> 
                            (catch ForEachDirFound(Top_Directory,FileOrDir)),
                            spawn(fun() -> ?MODULE:spread_directory(FileOrDir,Top_Directory,ForEachFileFound,ForEachDirFound) end);
                        false -> 
                            case ?IS_FILE(FileOrDir) of
                                false -> {error,not_a_file,FileOrDir};
                                true -> (catch ForEachFileFound(Top_Directory,FileOrDir))
                            end
                    end
                end,
            case file:list_dir(Dir) of      
                {error,_} -> ?FAILED_TO_LIST_DIR(Dir);
                {ok,List} -> lists:foreach(F,List)
            end
    end.    


函数spread_directory/4是通用的,它需要两个funs。一个乐趣:ForEachFileFound/2与最热门目录一起使用,找到的文件并对其执行任何操作,另一个乐趣:ForEachDirFound/2与最热门目录一起使用,它以所需的任何方式查找和使用该文件夹。

我用于此应用程序的启动脚本可确保erlang能够生成尽可能多的进程。进程完成对文件夹的索引编制后,将退出。

#!/usr/bin/env sh
echo "Starting File Scavenger System. Layer 1 on the P2P File Sharing System....."
erl \
    -name file_scavenger@127.0.0.1 \
    +P 13421779 \
    -pa ./ebin ./lib/*/ebin ./include \
    -mnesia dir '"./database"' \
    -mnesia dump_log_write_threshold 10000 \
    -eval "application:load(file_scavenger)" \
    -eval "application:start(file_scavenger)"

有一个gen_server将密集模块与数据库连接,在其中记录所有路径。下面显示了开始spread_directory工作的位置的片段:

handle_cast(index_dirs,#scavenger{directory_paths = Dirs} = State)->
{File,Folder} = case {State#scavenger.verbose,State#scavenger.verbose_to} of
{true,tty} ->
{
fun(TopDir,Fl)->
io:format(” File: ~p~n”,[Fl]),
file_scavenger_database:insert_file(filename:basename(Fl),file,Fl,TopDir,filename:extension(Fl))
end,
fun(TopDir,Fd) ->
io:format(” Folder: ~p~n”,[Fd]),
file_scavenger_database:insert_file(Fd,folder,Fd,TopDir,undefined)
end
};
{true,SomeFile}->
{
fun(TopDir,Fl)->
os:cmd(“echo File: ” Fl ” >> ” SomeFile),
file_scavenger_database:insert_file(filename:basename(Fl),file,Fl,TopDir,filename:extension(Fl))
end,
fun(TopDir,Fd)->
os:cmd(“echo Folder: ”
Fd ” >> ” SomeFile),
file_scavenger_database:insert_file(Fd,folder,Fd,TopDir,undefined)
end
}
end,
Main = fun(Dir) ->
error_logger:info_msg(“*** File scavenger Server indexing directory: ~p~n”,[Dir]),
spawn(fun() -> file_scavenger_utilities:spread_directory(Dir,Dir,File,Folder) end)
end,
lists:foreach(Main,Dirs),
{noreply,State};
handle_cast(stop, State) -> {stop, normal, State}.

可以在整个应用程序中找到更多源详细信息。您可以在以下位置找到应用程序的完整源代码和构建文件:
File_scavenger-1.0.zip

现在,我在服务器(HP Proliant G6,包含Intel处理器(2个处理器,每个4个核,每个核2.4 GHz速度,8 MB高速缓存大小),20 GB
RAM大小,1.5 TB磁盘空间)上启动应用程序。这些高功率机器已经可以使用了。应该在这两个机器之间复制系统数据库。每个服务器都运行Solaris
10(64位),其终端现在如下所示:

bash-3.00# sh file_scavenger.sh
Starting File Scavenger System. Layer 1 on the P2P File Sharing System.....
Erlang R14B03 (erts-5.8.4) [source] [smp:8:8] [rq:8] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.4  (abort with ^G)
(file_scavenger@127.0.0.1)1>
=INFO REPORT==== 18-Aug-2011::09:36:04 ===
Starting File Scavenger Database......
=INFO REPORT==== 18-Aug-2011::09:36:04 ===
Database Successfully Started....

=INFO REPORT==== 18-Aug-2011::09:36:04 ===
Starting File Scavenger Database......
=INFO REPORT==== 18-Aug-2011::09:36:04 ===
Database Successfully Started....

=INFO REPORT==== 18-Aug-2011::09:36:04 ===
File Scavenger Server starting with default verbose settings....

(file_scavenger@127.0.0.1)1> file_scavenger_server:index_dirs().

服务器开始运行,并向终端详细说明其找到的所有文件和文件夹。服务器配备了过多的RAM(20 GB)和交换空间(交换为16
GB)。但是,它运行了大约18个小时,最后,erlang虚拟机报告了这一点:

File: "/proc/4324/root/opt/csw/gcc4/share/locale/ja/LC_MESSAGES/gcc.mo"
 Folder: "/proc/4324/root/opt/csw/gcc4/share/locale/da"
 Folder: "/proc/4324/root/opt/csw/gcc4/share/locale/es/LC_MESSAGES"
 File: "/proc/4324/root/proc/4984/root/.thumbnails/normal/dc259e3897e8af4b379c6d956b6c1393.png"
 File: "/proc/4324/root/proc/4984/root/.thumbnails/fail/gnome-thumbnail-factory/223c19786421b7101d14075bdec46f61.png"
 File: "/proc/4324/root/opt/csw/gcc4/libexec/gcc/i386-pc-solaris2.10/4.5.1/install-tools/mkheaders"
 File: "/proc/4324/root/opt/csw/gcc4/libexec/gcc/i386-pc-solaris2.10/4.5.1/cc1plus"
 File: "/proc/4324/root/opt/csw/gcc4/lib/libsupc++.la"

Crash dump was written to: erl_crash.dump
eheap_alloc: Cannot allocate 153052320 bytes of memory (of type "heap").
Abort - core dumped
bash-3.00#

问题1. 使用如此强大的服务器,为什么操作系统无法为应用程序提供这种内存(这是唯一运行的应用程序)?

问题2. 指示我启动的Erlang仿真器能够生成所需数量的进程。价值+P 13421779。Erlang
VM是否无法访问此内存或未能将其分配给进程?

问题3.
对于Solaris,它看到一个过程:epmd,可能包含并启动数千个微线程。我可以对Solaris进行哪些配置以使其永不停止我的应用程序,无论它可能有多少“内存不足”?可用的交换空间为16
GB,RAM为20 GB,说实话,一定有问题。

问题4.
我可以对Erlang仿真器进行哪些配置,以避免这些堆内存崩溃转储,尤其是当服务器上可能需要的所有内存都可用时?如果Erlang仍然无法将此类内存分配给简单的文件系统索引器(严重并发),我将如何在该服务器上运行更多消耗内存的应用程序?

最后,欢迎进行其他所有为避免在此类功能强大的硬件上出现堆内存问题而进行的调整。提前致谢


问题答案:

我还没有时间查看源代码,但是这里有一些评论:

问题1.使用如此强大的服务器,为什么操作系统无法为应用程序提供这种内存(这是唯一运行的应用程序)?

因为Erlang VM尝试消耗的可用内存超过可用内存。

问题2.指示我启动的Erlang仿真器能够生成所需数量的进程。值+ P13421779。Erlang VM是否无法访问此内存或未能将其分配给进程?

否。如果您用完了所有进程,则Erlang VM会这样说(并且该VM仍将启动并运行):

=ERROR REPORT==== 18-Aug-2011::10:04:04 ===
Error in process <0.31775.138> with exit value: {system_limit,[{erlang,spawn_link,    [erlang,apply,[#Fun<shell.3.130303173>,[]]]},{erlang,spawn_link,1},{shell,get_command,5},    {shell,server_loop,7}]}

问题3.在Solaris中,它看到一个过程:epmd,可能包含并启动数千个微线程。我可以对Solaris进行哪些配置以使其永不停止我的应用程序,无论它可能有多少“内存不足”?可用的交换空间为16
GB,RAM为20 GB,说实话,一定有问题。

epmd是Erlang端口映射守护进程。它负责管理分布式Erlang,与您的单个Erlang应用程序无关。您应该寻找的过程将beam.smp很可能是名字。这些将显示Erlang
VM等的OS内存消耗。

问题4.我可以对Erlang仿真器进行哪些配置,以避免这些堆内存崩溃转储,尤其是当服务器上可能需要的所有内存都可用时?如果Erlang仍然无法将此类内存分配给简单的文件系统索引器(严重并发),我将如何在该服务器上运行更多消耗内存的应用程序?

Erlang VM应该能够使用计算机中的所有可用内存。但是,这取决于您的应用程序的编写方式。内存泄漏可能有很多原因:

  • 原子表填满(您创建了太多的唯一原子)
  • ETS或Mnesia表不会被垃圾收集(您不会删除旧的未使用元素)
  • 进程没有足够的内存(您产生了太多的进程)
  • 创建的二进制文件太多(您可能会保留未使用的对旧二进制文件的引用)


 类似资料:
  • 主要内容:src/runoob/heap/IndexMaxHeap.java 文件代码:一、概念及其介绍 索引堆是对堆这个数据结构的优化。 索引堆使用了一个新的 int 类型的数组,用于存放索引信息。 相较于堆,优点如下: 优化了交换元素的消耗。 加入的数据位置固定,方便寻找。 二、适用说明 如果堆中存储的元素较大,那么进行交换就要消耗大量的时间,这个时候可以用索引堆的数据结构进行替代,堆中存储的是数组的索引,我们相应操作的是索引。 三、结构图示 我们需要对之前堆的代码实现进行改造,

  • 问题内容: v8对单个对象的堆分配有限制吗? 在节点命令行上失败 另外,以脚本运行时失败并显示相同的错误 最后输出: 然而, 很好 编辑: 编辑2:即使这有效!v8的限制似乎适用于对象可以具有的属性数量? 另外,我发现了这个:https : //github.com/v8/v8/blob/master/src/objects.h#L2928 我想知道这是否相关。 问题答案: 事实证明,对字符串,对

  • 我使用的是ignite 2.9。本机持久性已禁用。 使用在堆缓存上启用 缓存配置。setOnheapCacheEnabled(真) 但我仍然可以在日志中看到堆外指标。 在将on heap设置为true后,它不应该只使用堆内存吗 什么类型的数据存储在堆外 在为堆上的默认数据区域定义的逐出策略为random2Lru和LRU的情况下,逐出如何工作

  • 问题内容: 具有100个属性的一个对象所消耗的存储空间是否与每个具有一个属性的100个对象所消耗的存储空间相同? 为一个对象分配多少内存? 添加属性时会使用多少额外空间? 问题答案: 指出,这不是一个容易回答的简单问题: JVM可以自由地以内部或大端或小端的任何方式存储数据,并具有一定的填充或开销,尽管基元必须表现得好像它们具有官方大小一样。 例如,JVM或本机编译器可能会决定将64位长块(如)存

  • 我们Java开发人员有时会使用来确保我们为每个特定于线程的堆栈提供了1MB的空间。现在,我经常感到困惑,JVM从哪里借用了1MB,从堆或系统内存中借用,或者Java为线程分配任何特定的内存。你能帮我理解一下吗? 此外,我们是否有一个可视化(插件)运行时工具,可以以可理解的方式显示堆和堆栈的内容? 提前感谢。

  • 主要内容:on-heap 堆内内存是什么?,JVM 堆内存是如何去划分的?,JVM 堆内存满了后会怎么样?,基于堆外内存解决系统 GC 卡顿问题今天给大家聊一个很有意思的知识,就是 off-heap 堆外内存,平时出去面试,或者研究一些技术的时候,经常可能会遇到 off-heap 堆外内存这个东西,但是很多人可能还不知道 off-heap 堆外内存到底是什么,所以今天就给大家来深入的分析一下。 on-heap 堆内内存是什么? 要说这个 off-heap 堆外内存,就得先说 on-heap 也就