R13B04在细化Binary heap
从github otp的更新日志可以清楚的看到otp R13B04在binary heap的细化上做了很多工作:
1. 提供参数 限制binary的最小limit.
2. binary_to_term 加多参数来保证安全, 对于外来binary解码的安全性检查 比如说 避免atom的滥用.
3. 更高效率的处理binary fragment.
4. 加强GC对binary碎片的回收操作.
这个对于服务器性能很大帮助.
从github otp的更新日志可以清楚的看到otp R13B04在binary heap的细化上做了很多工作:
1. 提供参数 限制binary的最小limit.
2. binary_to_term 加多参数来保证安全, 对于外来binary解码的安全性检查 比如说 避免atom的滥用.
3. 更高效率的处理binary fragment.
4. 加强GC对binary碎片的回收操作.
这个对于服务器性能很大帮助.
R13B03 binary vheap有助减少binary内存压力.
参看:http://www.erlang.org/download/otp_src_R13B03.readme
OTP-8202 A new garbage collecting strategy for binaries which is more
aggressive than the previous implementation. Binaries now has
a virtual binary heap tied to each process. When binaries are
created or received to a process it will check if the heap
limit has been reached and if a reclaim should be done. This
imitates the behavior of ordinary Erlang terms. The virtual
heaps are grown and shrunk like ordinary heaps. This will
lessen the memory footprint of binaries in a system.
原来的binary和其他类型的eterm是混在一起的,当进程的heap用完的时候,才进行GC,腾出空间。现在是把binary单独抽取出来,单独计数, 当binary用量过大的时候,马上就GC。
这个策略对于我们的服务器程序很有帮助,因为我们的服务器程序基本上包都是binary, 很容易出现binary无法及时回收,导致内存耗光的情况。
具体的改进效果待进一步的观察。
我们知道扩展erl有2种方法, driver和port. 这2个方法效率都低,因为都要经过 port机制,对于简单的模块,这个开销有时候是不可接受的。这时候nif来救助了。今天发布的R13B03已经支持了,虽然是实验性质的。 erl_nif的代表API functions for an Erlang NIF library。 参考文档:
erl_nif.html 和 erlang.html#erlang:load_nif-2 以及 reference_manual/code_loading.html#id2278318 。
我们来用nif写个最简单的hello, 来展现nif的威力和简单性。
不啰嗦,直接上代码:
root@nd-desktop:~/niftest# cat niftest.c
/* niftest.c */ #include "erl_nif.h" static ERL_NIF_TERM hello(ErlNifEnv* env) { return enif_make_string(env, "Hello world!"); } static ErlNifFunc nif_funcs[] = { {"hello", 0, hello} }; ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL)
root@nd-desktop:~/niftest# cat niftest.erl
-module(niftest). %-on_load(init/0). -export([init/0, hello/0]). init() -> ok=erlang:load_nif("./niftest", 0), true. hello() -> "NIF library not loaded".
编译:
root@nd-desktop:~/niftest# gcc -fPIC -shared -o niftest.so niftest.c -I /usr/local/lib/erlang/usr/include #你的erl_nif.h路径
运行:
root@nd-desktop:~/niftest# erl Erlang R13B03 (erts-5.7.4) [source][/source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]</code> Eshell V5.7.4 (abort with ^G) 1> c(niftest). {ok,niftest} 2> niftest:hello(). "NIF library not loaded" 3> niftest:init(). ok 4> niftest:hello(). "Hello world!" 5>
现在重新修改下 niftest.erl 把on_load的注释去掉
root@nd-desktop:~/niftest# erl Erlang R13B03 (erts-5.7.4) [source][/source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]</code> Eshell V5.7.4 (abort with ^G) 1> c(niftest). {ok,niftest} 2> niftest:hello(). "Hello world!" 3>
综述: nbif很简单,而且高效。
escript Erlang scripting support, 可以让erl模块转身变成unix script来使用,大大方便用户,具体的使用参看otp文档。我这里要演示的是些比较被忽视的高级特性:
首先crack erts/etc/common/escript.c:33 static int debug = 1; 让之显示调用参数。
root@nd-desktop:~# cat >factorial
[color=red]#!/usr/bin/env escript %% -*- erlang -*- %%! -smp enable -sname factorial -mnesia debug verbose[/color] main([String]) -> try N = list_to_integer(String), F = fac(N), io:format("factorial ~w = ~w\n", [N,F]) catch _:_ -> usage() end; main(_) -> usage(). usage() -> io:format("usage: factorial integer\n"), halt(1). fac(0) -> 1; fac(N) -> N * fac(N-1).
CTRL+D
root@nd-desktop:~# chmod +x factorial root@nd-desktop:~# ./factorial 10
[color=red]erl +B -boot start_clean -noshell -smp enable -sname factorial -mnesia debug verbose -run escript start -extra ./factorial 10[/color]
factorial 10 = 3628800
特性1:
摘抄文档。。。
On the third line (or second line depending on the presence of the Emacs directive), it is possible to give arguments to the emulator, such as
%%! -smp enable -sname factorial -mnesia debug verbose
Such an argument line must start with %%! and the rest of the line will interpreted as arguments to the emulator.
我们可以看到 这些选项被传递给了 erl
特性2:
-mode(compile).
这个选项是在escript.erl这个模块处理的。默认情况下 escript是被解释执行的,如果你的脚本很复杂,那么效率估计会是瓶颈。这种情况下, 你可以通过这个选项来让escript来先编译你的模块成opcode, 在vm里面运行。
特性3:
-d 选项 用来调试script的
-c 编译执行
-i 解释执行
-s 只检查不执行
root@nd-desktop:~# escript -d ./factorial 10
我们就可以看到 调试界面如下图
特性4:
可以把一个beam文件作为script
root@nd-desktop:/usr/src# cat hello.erl
-module(hello). -export([start/0,main/1]). main(_)-> start(). start()-> io:format("hello world~n",[]).
root@nd-desktop:/usr/src# erlc hello.erl root@nd-desktop:/usr/src# cat >hello
#!/usr/bin/env escript %% -*- erlang -*- %%! -smp enable -sname factorial -mnesia debug verbose
CTRL+D
root@nd-desktop:/usr/src# cat hello.beam >>hello root@nd-desktop:/usr/src# chmod +x hello root@nd-desktop:/usr/src# ./hello hello world
特性5:
可以把一个zip文件作为script
root@nd-desktop:/usr/src# cat hello.erl
-module(hello). -export([start/0,main/1]). main(_)-> start(). start()-> io:format("hello world, fac(10)=~w ~n",[fac:fac(10)]).
root@nd-desktop:/usr/src# cat fac.erl
-module(fac). -export([fac/1]). fac(0) -> 1; fac(N) -> N * fac(N-1).
root@nd-desktop:/usr/src# erlc *.erl root@nd-desktop:/usr/src# erl Erlang R13B03 (erts-5.7.4) [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.7.4 (abort with ^G) 1> zip:zip("hello.zip", ["hello.beam", "fac.beam"]). {ok,"hello.zip"} 2>
root@nd-desktop:/usr/src# cat >hello
#!/usr/bin/env escript %% -*- erlang -*- %%! -smp enable -sname factorial -mnesia debug verbose -escript main hello
CTRL+D
root@nd-desktop:/usr/src# cat hello.zip >>hello root@nd-desktop:/usr/src# chmod +x hello root@nd-desktop:/usr/src# ./hello hello world, fac(10)=3628800
特性6:
在独立的包里面 把escript伪装成我们的应用程序
root@nd-desktop:/usr/src# cat >hello.escript
-module(hello). -export([start/0,main/1]). main(_)-> start(). start()-> io:format("hello world~n",[]).
CTRL+D
root@nd-desktop:/usr/src# cp `which escript` hello root@nd-desktop:/usr/src# ./hello hello world
规则是 escript 改名成xxxx 执行xxxx的时候 实际上要读取的脚本是 xxxx.escript
综述: escript是很强大的 未来的erlang standalone全靠它。
erlang otp标准发布包里面的命令行工具都在bin目录下
dialyzer
erlc
escript
typer
erlang的这些命令行工具基本上都是erl模块的c的wrapper, 最后都是调用erl来运行相应的模块完成任务。
实验如下:
root@nd-desktop:~# touch test.erl root@nd-desktop:~# erlc -d test.erl erl -noinput -mode minimal -boot start_clean -s erl_compile compile_cmdline @cwd /root @files test.erl
首先crack erts/etc/common/escript.c:33 static int debug = 1; 让之显示调用参数
root@nd-desktop:~# escript test.erl erl +B -boot start_clean -noshell -run escript start -extra test.erl
我们可以清楚的看到是如何调用相应的模块的。
那我们再看下 erl
root@nd-desktop:/usr/src/otp_src_R13B03# cat bin/erl #!/bin/sh # # %CopyrightBegin% # # Copyright Ericsson AB 1996-2009. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. # # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. # # %CopyrightEnd% # ROOTDIR=/usr/src/otp_src_R13B03 BINDIR=$ROOTDIR/bin/i686-pc-linux-gnu EMU=beam PROGNAME=`echo $0 | sed 's/.*\///'` export EMU export ROOTDIR export BINDIR export PROGNAME exec $BINDIR/erlexec ${1+"$@"}
这个erl程序其实是个shell script, 简单的设置下环境变量 然后调用erlexec来调用相应的VM。
但是为什么其他的都是binary程序, 唯独erl是script呢。 我能想出的唯一理由是: OTP team的人为了我们方便修改erl的行为 特地用脚本来写, 这样用户就可以很方便的定制erl.
如果我的猜测没错的话,那么erlang真的很细心。
GNU libreadline 为行编辑提供了统一的接口和方便的编辑能力,在使用中感觉非常爽。但是不是所以的应用程序都使用了readline库来读取用户输入,大部分C程序只是简单的调用fgets。这样的程序在输入的时候非常痛苦。比如erl,为了移植性没用到readline,而是自己实现了类似readline那样的基本的行编辑,但是非常难用,例如不支持CTRL A, CTRL E等等。
这时候rlwrap来救助了。
rlwrap runs the specified command, intercepting user input in order to provide readline’s line editing, persistent history and completion.
简单的说 这个程序就是让不支持readline的程序也可以享用这个库的好处。
在ubuntu下只要简单的 apt-get -y install rlwrap 就安装好了
使用也很简单:
rlwrap cmd
比如 rlwrap erl 这样就可以在erl shell里面以熟悉的emacs按键快速输入,舒服哦。
在linux shell下还可以在.profile里面加入别名, 比如
alias erl='rlwrap erl'
那么就不露神色的修改了erl的行为。
PS. piboyeliu同学说:
新版本的要使用 rlwrap -a erl 才可以正确运行
昨天新发布的Go还是很不错的,而且随机带了个emacs的模式 用起来很方便。
root@nd-desktop:/usr/src/golang# pwd /usr/src/golang root@nd-desktop:/usr/src/golang# ls misc/emacs/ go-mode.el go-mode-load.el root@nd-desktop:/usr/src/golang# cp misc/emacs/*.el ~/.emacs.d root@nd-desktop:/usr/src/golang# cat >> ~/.emacs <code>(setq load-path (cons (expand-file-name "~/.emacs.d/") load-path)) (require 'go-mode-load)</code>
CTRL+D
搞定收工。
Recent Comments