浏览 1671 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-05-12
最后修改:2009-09-04
http://noss.github.com/2009/04/02/constant-pool-erlang-hack.html
原文地址 2009-04-02 Erlang R12B-0 added a per-module memory area for constants, the literal values in a module are stored there. Before, they were allocated on the heap every time they were referenced. This meant that some kinds of optimization that avoided literal lookup-tables became irrelevant in one go (without even recompiling the source). A great example of the kind of improvements that OTP focus on: removing speed-bumps to having beautiful code. From the release notes of R12B-0 OTP-6850: Literal lists, tuples, and binaries are no longer constructed at run-time as they used to be, but are stored in a per-module constant pool. Literals that are used more than once are stored only once. This is not a change to the language, only in the details of its implementation. Therefore, the implications of this change is described in the Efficiency Guide. The erlang efficiency guide on constant pools pretty much say the same thing. But Björn Gustavsson adds this very interesting remark about unloading a module and the constant pool. If one has very assymetric access patterns to some value, Maybe millions of times more reads than updates, and this is a measured problem, one can reach for hacks such as generating a module containing the values as literals and thus have a global configuration value that will not grow your heap unecessary. But… As always, remember when to optimize. ------------------------------------------------------------------------- 在对beam_load.c:read_literal_table(LoaderState* stp)函数打了补丁 显示出这个模块的literal数目和类型我们可以看到这样的结果: module base64: num_literals[4] 0: tag[1], size[5], term["="] 1: tag[1], size[6], term["=="] 2: tag[3], size[131], term[{65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,54,55,56,57,43,47}] 3: tag[3], size[1086], term[{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}] 这个是标准库base64.erl的literal. 从统计可以看出 atom本身已经不是literal, 这里大部分的literal是1,3的类型也是据说是tuple和list, 0是代表binary. 你在程序里面形如: [1,2,3,4]. {1,2,3,4}. <<1,2,3,4>>. 的编译器常量就会被放在模块的literal表格里面 在beam加载的时候 这些常量就创建完毕在内存里,同时调整涉及这些常量的模块的op code,让它们直接使用这些常量,而不是每次新建一个。 这样的优化对于base64或者c程序出身的人很有帮助,应为我们最擅长查表格,常数的查询时间。那么现在我们也可以在erlang下这么用了,看下base64.erl代码 %% arrays for character translation %% value -> base64 (zero-based) encode_tuple() -> {$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $+, $/}. %% base64 -> value (one-based) decode_tuple() -> {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, -1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}. %% accessors b64e(X, T) -> element(X+1, T). b64d(X, T) -> b64d_ok(element(X, T)). -spec b64d_ok(non_neg_integer()) -> non_neg_integer(). b64d_ok(N) when N >= 0 -> N. 舒服吧! 很多时候如果你的erl程序设计到常量的问题 有效率问题的时候 你可以动态生成一个erl文件然后用编译器编译再动态加载,最大程度的提高效率。 你的这些常量不参与GC, 无需创建,无需拷贝,这就是它的意义! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-05-13
老大在孜孜不倦的发现erlang的精妙之处哈哈。
引用:http://www.erlang.org/doc/efficiency_guide/processes.html#8.2 里面的描述: 8.2.1 The constant pool Constant Erlang terms (also called literals) are now kept in constant pools; each loaded module has its own pool, constant terms will no longer build the tuple every time it is called. But if a constant is sent to another process (or stored in an ETS table), it will be copied. The copying of constants might be eliminated in a future release. 呵呵,不断变化中... |
|
返回顶楼 | |
发表时间:2009-09-04
>> As far as I know, these constants will not be copied to the private
>> heaps of the processes. > > You're talking about current Erlang releases, right? How does that > work with module reloading? E.g., if foo:bar/0 returns a constant > complex data structure and the result is not copied into the calling > process's private heap, what happens when a module is purged while a > process is still holding onto a reference to the data structure? The data will be copied to the heap of each process that has a reference to the data before the module is purged. |
|
返回顶楼 | |