- 浏览: 101059 次
- 性别:
- 来自: 杭州
最新评论
-
johncan:
但是如果绑定错误,反而会有反效果,请问如何看是否绑定错误?是否 ...
erlang程序优化点的总结(持续更新) -
mahengyang:
如何使用mnesia:select/4分页查询%%对事务封装了 ...
mnesia监控项目 -
zjjxxl:
mysql代码高手,我们这里mysql5.6长时间运行内存过高 ...
innodb对B树游标的定位过程以及对“小于(等于)B树最小记录”的特殊处理 -
wqtn22:
是原创啊,霸爷mryufeng认证的,增加引用计数和减少引用计 ...
erlang NIF部分接口实现(三)持久资源 -
magicxiao:
enif_release_resource当引用计数为0的时候 ...
erlang NIF部分接口实现(三)持久资源
NIF的内存管理接口为enif_alloc/enif_free。
erl_nif.c
void* enif_alloc(size_t size)
{
return erts_alloc_fnf(ERTS_ALC_T_NIF, (Uint) size);
}
erl_alloc.h
ERTS_ALC_INLINE
void *erts_alloc_fnf(ErtsAlcType_t type, Uint size)
{
return (*erts_allctrs[ERTS_ALC_T2A(type)].alloc)(
ERTS_ALC_T2N(type),
erts_allctrs[ERTS_ALC_T2A(type)].extra,
size);
}
可以看出NIF的内存分配将直接通过ERTS_ALC_T_NIF对应的虚拟机内存分配器ERTS_ALC_A_DRIVER分配内存,ERTS_ALC_A_DRIVER也是利用alloc_util框架实现的内存分配器,详细文档请阅读http://www.erlang.org/doc/man/erts_alloc.html。
void enif_free(void* ptr)
{
erts_free(ERTS_ALC_T_NIF, ptr);
}
void erts_free(ErtsAlcType_t type, void *ptr)
{
(*erts_allctrs[ERTS_ALC_T2A(type)].free)(
ERTS_ALC_T2N(type),
erts_allctrs[ERTS_ALC_T2A(type)].extra,
ptr);
}
对于NIF的内存释放过程也是如此,erlang虚拟机内存管理是一个非常庞杂的系统,此处将不进行分析,读者可以简单地将其看作malloc/free接口(虽然其实现要复杂的多)。
NIF的类型系统接口大同小异,基本上对于每种类型,都有一对make和get接口,稍微特殊的是binary类型。
首先来看NIF的利用进程堆分配内存的接口,它们是make类函数均要使用到的:
static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need)
{
Eterm* hp = env->hp;
env->hp += need;
if (env->hp <= env->hp_end) {
return hp;
}
/* env的堆来自于其附着的进程的堆, 若env的堆有足够大的空间,则直接在堆内分配,否则将扩大堆 */
return alloc_heap_heavy(env, need, hp);
}
static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp)
{
env->hp = hp;
if (env->heap_frag == NULL) {
ASSERT(HEAP_LIMIT(env->proc) == env->hp_end);
HEAP_TOP(env->proc) = env->hp;
}
else {
env->heap_frag->used_size = hp - env->heap_frag->mem;
ASSERT(env->heap_frag->used_size <= env->heap_frag->alloc_size);
}
hp = erts_heap_alloc(env->proc, need, MIN_HEAP_FRAG_SZ);
/* 此处扩大进程的堆 */
env->heap_frag = MBUF(env->proc);
env->hp = hp + need;
env->hp_end = env->heap_frag->mem + env->heap_frag->alloc_size;
return hp;
}
Eterm*erts_heap_alloc(Process* p, Uint need, Uint xtra)
{
ErlHeapFragment* bp;
Eterm* htop;
Uint n;
n = need + xtra;
bp = MBUF(p);
if (bp != NULL && need <= (bp->alloc_size - bp->used_size)) {
Eterm* ret = bp->mem + bp->used_size;
bp->used_size += need;
return ret;
}
/* 进程的堆在开始时是和进程栈连在一起的,当堆不断扩大,直到不足时,分配器将为堆产生一个新的堆内存片段,之后的内存分配都将在新的堆内存片段上进行,这也是一种懒惰方法 */
bp = (ErlHeapFragment*)
ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP_FRAG, ERTS_HEAP_FRAG_SIZE(n));
/* 分配新的堆内存片段,使用ERTS_ALC_T_HEAP_FRAG对应的ERTS_ALC_A_EHEAP分配器分配内存,它也是一个通过alloc_util框架实现的内存分配器 */
htop = HEAP_TOP(p);
if (htop < HEAP_LIMIT(p)) {
*htop = make_pos_bignum_header(HEAP_LIMIT(p)-htop-1);
HEAP_TOP(p) = HEAP_LIMIT(p);
}
bp->next = MBUF(p);
MBUF(p) = bp;
/* 更新进程的堆内存片段信息,堆内存片段是一个单向列表,这也保证了进程堆的自由扩大 */
bp->alloc_size = n;
bp->used_size = need;
MBUF_SIZE(p) += n;
bp->off_heap.first = NULL;
bp->off_heap.overhead = 0;
return bp->mem;
}
#define ERTS_HEAP_ALLOC(Type, Size) \
erts_alloc((Type), (Size))
/* 然后构建一个进程binary的结构保存刚刚分配的大额binary */
ERTS_GLB_INLINE Binary *erts_bin_nrml_alloc(Uint size)
{
Uint bsize = ERTS_SIZEOF_Binary(size) + CHICKEN_PAD;
void *res;
res = erts_alloc(ERTS_ALC_T_BINARY, bsize);
ERTS_CHK_BIN_ALIGNMENT(res);
return (Binary *) res;
}
binary构造:
Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
{
if (bin->bin_term != THE_NON_VALUE) {
return bin->bin_term;
}
else if (bin->ref_bin != NULL) {
Binary* bptr = bin->ref_bin;
ProcBin* pb;
Eterm bin_term;
/* !! Copy-paste from new_binary() !! */
pb = (ProcBin *) alloc_heap(env, PROC_BIN_SIZE);
pb->thing_word = HEADER_PROC_BIN;
pb->size = bptr->orig_size;
pb->next = MSO(env->proc).first;
MSO(env->proc).first = (struct erl_off_heap_header*) pb;
pb->val = bptr;
pb->bytes = (byte*) bptr->orig_bytes;
pb->flags = 0;
OH_OVERHEAD(&(MSO(env->proc)), pb->size / sizeof(Eterm));
bin_term = make_binary(pb);
if (erts_refc_read(&bptr->refc, 1) == 1) {
/* Total ownership transfer */
bin->ref_bin = NULL;
bin->bin_term = bin_term;
}
return bin_term;
}
else {
flush_env(env);
bin->bin_term = new_binary(env->proc, bin->data, bin->size);
cache_env(env);
return bin->bin_term;
}
}
对于64位系统和32位系统小数,直接可以从Eterm中提取数据内容,对于32位大数,需要一个较复杂的转换过程。
int enif_get_string(ErlNifEnv *env, ERL_NIF_TERM list, char* buf, unsigned len,
ErlNifCharEncoding encoding)
{
Eterm* listptr;
int n = 0;
ASSERT(encoding == ERL_NIF_LATIN1);
if (len < 1) {
return 0;
}
while (is_not_nil(list)) {
if (is_not_list(list)) {
buf[n] = '\0';
return 0;
}
listptr = list_val(list);
if (!is_byte(*listptr)) {
buf[n] = '\0';
return 0;
}
buf[n++] = unsigned_val(*listptr);
if (n >= len) {
buf[n-1] = '\0'; /* truncate */
return -len;
}
list = CDR(listptr);
}
buf[n] = '\0';
return n + 1;
}
主要的类型系统接口已经分析完了,对于每个类型,都有一个get和make函数,binary类例外,get函数会取得类型的数据内容,make函数会为类型分配内存,并构造类型。
发表评论
-
erlang虚拟机topology不符导致启动后crash
2013-12-24 15:49 2009线上有一台t4的机器,这些机器的cpu topo是经过伪造 ... -
erlang程序优化点的总结(持续更新)
2013-03-03 15:40 11602转载请注明出处 注意,这里只是给出一个总结,具体性能 ... -
erlang:ports与erlang:processes引发的问题
2012-07-29 22:57 3507最近4399的同学遇到一个问题,以下是他的描述: “用 ... -
erlang NIF部分接口实现(五)复用driver功能的接口
2012-07-22 22:08 2369NIF除了自身提供的功能外,还封装了一系列driver的功能, ... -
erlang NIF部分接口实现(四)消息发送
2012-07-22 21:42 2655erlang中不能没有消息和异步过程,NIF也必须有此项能力, ... -
erlang NIF部分接口实现(三)持久资源
2012-07-22 21:05 2573持久资源是NIF中一类非常有用接口,可以把资源看成各种数据结构 ... -
erlang NIF部分接口实现(一)加载过程及编写框架
2012-07-22 18:18 7879最近在项目中频繁用到erlang的NIF接口,以扩展erlan ...
相关推荐
在Erlang生态系统中,Native Implemented Functions (NIFs) 是一种机制,允许开发者用其他语言(如C、C++或Rust)编写性能关键部分的代码,然后在Erlang虚拟机(VM)中调用。Rustler是一个库,专门用于简化使用Rust...
- **内存管理**:Erlang VM负责内存的分配和回收,但NIF代码需要遵循特定的规则来操作Erlang术语,如使用`enif_alloc`分配内存,然后用`enif_free`释放。 - **错误传播**:Erlang的错误处理机制与C不同,所以要确保...
在Erlang中,`NIF (Native Implemented Functions)` 是一种机制,允许开发者使用其他语言(如C或Rust)...通过理解`rustler_macro`的过程宏和Erlang NIF的生命周期,开发者可以轻松地将Rust功能集成到Erlang系统中。
在Erlang中,为了实现与C或其他低级语言的高效交互,Erlang提供了一个名为`erl_nif`的接口。本文将深入探讨`erl_nif`,了解它是如何扩展Erlang的功能,并讨论如何使用它来提升性能。 `erl_nif`(Erlang NIF,Native...
Windows下使用NIF扩展Erlang完整例子,包含nif工程项目,erlang引用例子。 配套文章:http://blog.csdn.net/mycwq/article/details/17527485
Erlang与C语言接口主要通过两种方式实现:一种是将C语言编写的代码直接嵌入到Erlang程序中;另一种是通过进程间通信(IPC)的方式让Erlang与C语言程序进行交互。Erlang倾向于采用第二种方式,即进程间通信,来与C语言...
在IT领域,Erlang是一种强大的并发编程语言,主要用于构建高可用性、容错性和分布式系统。它以其轻量级进程、消息传递和热代码升级等特性而闻名。Unix(包括其衍生版本如Linux)是广泛使用的操作系统,具有丰富的...
示例Rustler是一个用于以安全的Rust代码编写Erlang NIF的库。 这意味着应该没有任何办法。 入门指南 示例Rustler是一个用于以安全的Rust代码编写Erlang NIF的库。 这意味着应该没有办法使BEAM(Erlang VM)崩溃。 该...
Rust 中的 Erlang NIF 这是一个如何在 Rust 中实现 NIF 的示例。 它对我有用,也可能对你有用,但如果它吃掉了你的作业,请不要生气。 虽然这将是可行的写现实世界的代码下面这个例子,因为整个erl_nif.h接口可用...
此外,提供的"erlang的timer和实现机制.pdf"和"更多erlang资料下载.txt"也是进一步学习和研究的好资源。 总之,Erlang的timer模块是其强大并发能力的一个体现,通过熟练掌握这一部分,开发者可以构建出更加高效和...
这是第一卷。 在2008 CN Erlounge III的“Erlang应用程序接口”讲演的视频。PPT等其它资料在这里: http://blog.csdn.net/aimingoo/archive/2009/01/14/3777765.aspx 有关信息参见: ...
Rustler会自动处理内存管理、错误处理和类型转换,确保NIF函数在Erlang VM中正确运行。 在Erlang应用中,这些NIF函数可以通过标准的Erlang/Elixir接口调用,就像调用普通的Erlang模块一样。这样,开发者可以在保持...
2. **内存管理**:Erlang的垃圾回收机制与C++或Java不同,`erl_protobuffs`充分利用了这一特性,优化了内存管理和对象生命周期,减少了不必要的内存开销。 3. **集成性**:由于Erlang主要用于构建分布式系统,`erl_...
**enif_protobuf** 是一个基于 **Erlang ...总之,enif_protobuf是Erlang社区对Google Protobuf的一种强大实现,通过Erlang NIF机制实现了高性能的数据序列化和反序列化,简化了Erlang系统与其他系统之间的数据交换。
- **Erlang模块**:Erlang代码部分,定义了与NIF交互的接口函数,这些函数在Erlang代码中可以像普通函数一样调用。 - **NIF接口定义**:Erlang模块中会有`erlang:nifEXPORTS`列表,列出所有暴露给Erlang的NIF函数...
ErlPuzzle - Erlang 的 libpuzzle NIF Puzzle 库旨在快速找到视觉上相似的图像(gif、png、jpg),即使它们已被调整大小、重新压缩、重新着色或稍微修改。 该库是免费的、轻量级的但非常快速、可配置、易于使用,...
5. **类型系统** 虽然Erlang是动态类型的语言,但它也有一些静态类型检查的特性。查看源码,可以理解Erlang如何在运行时进行类型检查。 6. **模式匹配** 模式匹配是Erlang的一大特色,它在函数调用、解构等场景中...
我在Erlounge III大会上的讲演PPT。 相关的视频在这里: http://groups.google.com/group/erlang-china/browse_thread/thread/2154c39503795edc