一、前提说明
1. 项目本身为了简单,将所有的beam文件最终都部署在同一个ebin目录下(无层次结构),包括第三方deps,目录结构如下:
2. deps中使用到了esqlite这个开源库(esqlite),这是个基于nif的erlang sqlite
二、问题说明
在我给esqlite添加热更新支持之后,遇到个问题:
strace:[{esqlite3_nif,prepare,
[<
>,#Ref,,"select * from t_job"],
[]},
{esqlite3,prepare,3,[{file,"src/esqlite3.erl"},{line,229}]},
{esqlite3,q,3,[{file,"src/esqlite3.erl"},{line,75}]},
跟踪时发现在reload时nif的两个static resource指针被重置了,这两个resource初始化代码如下:
static ErlNifResourceType *esqlite_connection_type = NULL; static ErlNifResourceType *esqlite_statement_type = NULL; rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_connection_type", destruct_esqlite_connection, ERL_NIF_RT_CREATE, NULL); if(!rt) return -1; esqlite_connection_type = rt; rt = enif_open_resource_type(env, "esqlite3_nif", "esqlite_statement_type", destruct_esqlite_statement, ERL_NIF_RT_CREATE, NULL); if(!rt) return -1; esqlite_statement_type = rt;
整个工程中没有任何地方显示的释放了以上两个resource,而nif的机制似乎也没有相关的说明。顺手抓了vmmap看了看,发现个异常情况:
看样子,nif在reload时重新加载了另外一个同名so,问题是为什么code path中有重复的内容出现?看了看代码中引导的deps,想起来mochiweb是有这样的机制的:自动解决依赖目录,实现在 mochiapp_deps.erl(这是个mochiweb的代码模板文件),至此问题就好解决了,简单屏蔽掉mochiweb的这个机制即可。