erlang 代码加载和热替换实验


主要涉及到的模块是code模块
 
 
 
code:purge---------------------------------------------------------------------------------------------------------------
清理内存中的代码

purge(Module) -> boolean() ,不论是否旧代码被使用都清理,杀死使用旧代码的进程

Types:

Module = module()

Purges the code for Module, that is, removes code marked as old. If some processes still linger in the old code, these processes are killed before the code is removed.

Returns true if successful and any process needed to be killed, otherwise false.

 

如果旧的代码还被使用就不能清理,返回false,否则清理,返回true

soft_purge(Module) -> boolean()

Types:

Module = module()

Purges the code for Module, that is, removes code marked as old, but only if no processes linger in it.

Returns false if the module could not be purged due to processes lingering in old code, otherwise true.

---------------------------------------------------------------------------------------------------------------------------

 
相关方法
all_loaded:返回已经加载到内存的模块和文件

all_loaded() -> [{Module, Loaded}]

Types:

Module = module()
Loaded = loaded_filename()
loaded_filename() = (Filename :: file:filename())
                  | loaded_ret_atoms()
Filename is an absolute filename
loaded_ret_atoms() = cover_compiled | preloaded

Returns a list of tuples {Module, Loaded} for all loaded modules. Loaded is normally the absolute file name, as described for is_loaded/1.

例如:

[{io,"d:/PROGRA~1/erl5.9/lib/stdlib-1.18/ebin/io.beam"},

 {erl_distribution,"d:\\PROGRA~1\\erl5.9/lib/kernel-2.15/ebin/erl_distribution.b

eam"},

 {erl_epmd,"d:\\PROGRA~1\\erl5.9/lib/kernel-2.15/ebin/erl_epmd.beam"},

 {zlib,preloaded},

 {error_handler,"d:\\PROGRA~1\\erl5.9/lib/kernel-2.15/ebin/error_handler.beam"},

...]

---------------------------------------------------------------------------------------------------------------------------

获得磁盘文件模块名,二进制代码,完整路径

 

{M, B, F} = code:get_object_code(Name),
code:get_object_code(mod_player).
{mod_player,<<70,79,82,49,0,0,82,76,66,69,65,77,65,116,
              111,109,0,0,4,222,0,0,0,100,10,109,111,...>>,
            "d:/Work_Onepiece/angel_game/trunk/project/ebin/mod_player.beam"}
 
加载磁盘文件到内存,可以远程调用=====
code:load_binary(M,F,B).  

load_binary(Module, Filename, Binary) ->
               {module, Module} | {error, What}

Types:

Module = module()
Filename = loaded_filename()
Binary = binary()
What = badarg | load_error_rsn()
loaded_filename() = (Filename :: file:filename())
                  | loaded_ret_atoms()
loaded_ret_atoms() = cover_compiled | preloaded

This function can be used to load object code on remote Erlang nodes. The argument Binary must contain object code for Module. Filename is only used by the code server to keep a record of from which file the object code for Module comes. Accordingly, Filename is not opened and read by the code server.

Returns {module, Module} if successful, or {error, sticky_directory} if the object code resides in a sticky directory, or {error, badarg} if any argument is invalid. Also if the loading fails, an error tuple is returned. See erlang:load_module/2 for possible values of What.

---------------------------------------------------------------------------------------------------------------------------

code:load_file
加载文件到内存,老的标识为老的
 
---------------------------------------------------------------------------------------------------------------------------
module_info
显示模块信息,版本,路径等
 
---------------------------------------------------------------------------------------------------------------------------
erlang:load_module/2
 
 
 
 
 
 
 
注意:
code:all_loaded():是已经加载过,使用过的代码,在目录下但是没有加载的并不会在这个里面
 
 
1. 测试code:soft_purge什么情况下会清空失败,
   Purges the code for Module, that is, removes code marked as old, but only if no processes linger in it.

   Returns false if the module could not be purged due to processes lingering in old code, otherwise true.

   有正在执行中的代码,不能清除,返回值false, 可以被清除返回true
 
 
2. purge一定会清除老代码,但是,根据是否有进程在使用返回值不同
purge(Module) -> boolean()

Types:

Module = module()

Purges the code for Module, that is, removes code marked as old. If some processes still linger in the old code, these processes are killed before the code is removed.

Returns true if successful and any process needed to be killed, otherwise false.

 
 
 
我们为了明确erlang新老代码,和清除代码的实际过程做测试
 
一.  启动erlang shell,对未加载的模块执行 
      purge          ->  false, 即使不存在的模块也会返回 false,说明只要内存没有就不操作
      soft_purge   ->  true, 说明只要内存没有就不操作.
二. 启动erlang shell, 对加载的模块执行
      purge         ->  false, 说明加载过也是可以正常清除的,而且返回false,说明只要没有代码执行中就会返回false
      soft_purge  ->  true, 说明只要没有代码执行中就可以正常清除
 
三. 启动erlang shell, 对代码执行中(通过设置递归方法)的模块执行
     purge           ->  false,   这个就很奇怪,可能的原因是代码没有变化,这个是正常的,Module中有进程执行中,我们执行purge的时候是将老代码移除,这时还没有老代码所以没事
     soft_purge    ->  true,   这也比较奇怪,可能原因同上,同上,但是如果我们再次load以后在执行purge和soft_purge就需会考虑标识为老代码的代码了
 
四. 启动erlang shell, 调用load_tests方法 t/1 输出当前ver
     然后修改编译代码,再次调用 t/1 输出的ver和之前的一样
     我们执行 code:load_file 加载模块, 再次执行t/1 这样返回的就是新的代码版本
 
五. 
1> code:is_loaded(load_tests).
false
2> load_tests:t().     %第一次加载
ver5
ok
3> code:is_loaded(load_tests).    
{file,"d:/Work_Onepiece/angel_game/trunk/project/ebin/load_tests.beam"}
6> code:load_file(load_tests).      %加载新代码, 上个版本的系统维护为老版本代码,如果老版本已经维护了一份代码的话这里就会出错
{module,load_tests}
7> code:load_file(load_tests).      %我们再次执行load_file就报错了
=ERROR REPORT==== 5-Sep-2012::14:03:15 ===
Loading of d:/Work_Onepiece/angel_game/trunk/project/ebin/load_tests.beam failed: not_purged
=ERROR REPORT==== 5-Sep-2012::14:03:15 ===
Module load_tests must be purged before loading
{error,not_purged}
 
六.
        1> code:load_file(load_tests).  %第一次加载
{module,load_tests}
2> code:load_file(load_tests).  %加载新代码, 上个版本的系统维护为老版本代码,如果老版本已经维护了一份代码的话这里就会出错
{module,load_tests}
3> code:load_file(load_tests).  %再次load就会失败,已经有两个版本代码在内存中了, 如果不purge就无法load,二purge是指的将系统维护的老代码移除掉
=ERROR REPORT==== 5-Sep-2012::14:11:59 ===
Loading of d:/Work_Onepiece/angel_game/trunk/project/ebin/load_tests.beam failed: not_purged
=ERROR REPORT==== 5-Sep-2012::14:11:59 ===
Module load_tests must be purged before loading
{error,not_purged}
 
    
.测试跨节点执行 load_file, 
    启动两个节点,然后执行 t方法,修改文件
    load_binary(Module, Filename, Binary) 方法中有一句话This function can be used to load object code on remote Erlang nodes
    那么我们看看它到底是什么作用,我们测试下一个节点下没有一个文件的情况
    
    
   
 
第一个节点---------------------------------------
(t1@QIAO)1> net_adm:ping('t@QIAO').
pong
(t1@QIAO)2> nodes().
[t@QIAO]
(t1@QIAO)3> load_tests:t().
ver2
ok
(t1@QIAO)4> code:load_file(load_tests).
{module,load_tests}
(t1@QIAO)5> load_tests:t().
ver3
ok
(t1@QIAO)6> rpc:call('t@QIAO', code, load_file, [load_tests]).
{module,load_tests}
(t1@QIAO)7>
 
第二个节点---------------------------------------
(t@QIAO)1> load_tests:t().
ver2
ok
(t@QIAO)2> load_tests:t().
ver2
ok
(t@QIAO)3> load_tests:t().
ver3
ok
(t@QIAO)4>
 
证明是可以的
 
 
code:purge(load_tests).
code:soft_purge(load_tests).
code:load_file(load_tests).
code:is_loaded(load_tests).
 
load_tests:t().
load_tests:linger().
load_tests:lt().
 
 net_adm:ping('t@QIAO').
 
那么我们让第二个节点没有load_tests文件来看
 
存在源文件的节点-----------------------------------------------------
(t@QIAO)1> loaded_tests:t().
ver3
ok
(t@QIAO)2> {M, B, F} = code:get_object_code(loaded_tests).
{loaded_tests,<<70,79,82,49,0,0,6,68,66,69,65,77,65,116,
                111,109,0,0,0,131,0,0,0,18,12,108,111,...>>,
              "d:/ErlangWork/my_test_project/ebin/loaded_tests.beam"}
(t@QIAO)3> rpc:call('t1@QIAO', code, load_binary, [M,F,B]).
{module,loaded_tests}
(t@QIAO)4>
 
不存在源文件的节点-----------------------------------------------------
C:\Users\Administrator\Desktop>erl -sname t1
Eshell V5.9  (abort with ^G)
(t1@QIAO)1> net_adm:ping('t@QIAO').
pong
(t1@QIAO)2> loaded_tests:t().
** exception error: undefined function loaded_tests:t/0
(t1@QIAO)3> loaded_tests:t().
ver4
ok
(t1@QIAO)4>
 
证明是可用的
 
 
 
结论:
 
A. code:load_file :将新的代码加载到内存中,内存中如果已经存在此模块代码那么标识为老的(如果有进程正在使用(一般是递归或者循环)的话那么还是可以用老版本),如果内存中已经存在此模块的老版本代码,则此方法会返回not_purded错误,执行执行 purde后才能将新的文件加载到内存,无论内存中存在几个版本,新的进程一定会使用新版本代码.
 
 
当内存中已经存在一个模块的代码的时候,我们再执行load_file就会提示not_purded错误,如果我们purde这个模块后就可以执行load_file了,但是只能执行一次,再次执行就会报错,而当我们系统还没有load过代码的话那么可以执行两次,第三次才会报错
 
B. code:purge/1 soft_purge/1,仔细看这两个方法的说明,这两个方法的作用是将标识为老的代码remove掉,只是老代码有可能正在被使用,这个要注意.
 
C. 关注下 load_binary(Module, Filename, Binary) --This function can be used to load object code on remote Erlang nodes
   请看上面的测试七, 目前的理解就是,即使这个节点搜索的目录下面都不包含一个模块,那么我们也可以远程让这个节点可以加载一个模块的代码
 
 
扩展阅读:
 
    code:load_binary/3 方法无论执行多少次都不会说源代码已存在
    我们看看到底成功还是没有成功, -->每次都会成功, 原则就是如果这个模块没有老代码那么将现在代码标识为老代码,如果已经存在老代码,那么执行清理(如果有进程在使用那么kill)
    简单说 load_binary = code:purde >> code:load_file
 

posted on 2012-09-05 16:12  fangjie008  阅读(1932)  评论(0编辑  收藏  举报

导航