如果你在Eos上发布一个智能合约,细心点的话可能会发现一个问题,就是你发布后代码所占的ram远比你的编译后的wasm代码和abi文件的总字节数大的多,如果减去abi文件所占的存储空间,你会发现,所占的内存刚好是代码大小的10倍。这是一个有意思的问题。答案就在如下的代码中:
找到libraries/chain/eosio_contract.cpp这个文件的
void apply_eosio_setcode(apply_context& context)
这个函数,你会发现如下的代码:
int64_t code_size = (int64_t)act.code.size();
int64_t old_size = (int64_t)account.code.size() * config::setcode_ram_bytes_multiplier;
int64_t new_size = code_size * config::setcode_ram_bytes_multiplier;
...
if (new_size != old_size) {
context.add_ram_usage( act.account, new_size - old_size );
}
也即这里把code_size乘以了一个常量:config::setcode_ram_bytes_multiplier,这个常量在config.hpp中定义如下:
const static uint32_t setcode_ram_bytes_multiplier = 10; ///< multiplier on contract size to account for multiple copies and cached compilation
也即为常数10,这就有点奇怪了,为什么要把存储空间乘以十呢。看注释可以看出点名堂来:
multiplier on contract size to account for multiple copies and cached compilation
也即这个乘数是为了将wasm代码的多份拷贝和编译缓存所占的内存计算在内。找到libraries/chain/include/eosio/chain/wasm_interface.hpp,你会发现如下的变量:
map<uint64_t, std::unique_ptr<wasm_instantiated_module_interface>> instantiation_cache;
这个变量即是用来在缓存wasm代码的。
wasm的wabt模式和wavm运行模式都对wasm_instantiated_module_interface这个类进行继承
wasm的wavm运行模式下为:
class wavm_instantiated_module : public wasm_instantiated_module_interface {
std::vector<uint8_t> _initial_memory;
//naked pointer because ModuleInstance is opaque
//_instance is deleted via WAVM's object garbage collection when wavm_rutime is deleted
ModuleInstance* _instance;
std::unique_ptr<Module> _module;
}
wasm的wabt模式的定义如下:
class wabt_instantiated_module : public wasm_instantiated_module_interface {
private:
std::unique_ptr<interp::Environment> _env;
DefinedModule* _instatiated_module; //this is owned by the Environment
std::vector<uint8_t> _initial_memory;
TypedValues _params{3, TypedValue(Type::I64)};
std::vector<std::pair<Global*, TypedValue>> _initial_globals;
Limits _initial_memory_configuration;
Executor _executor;
}
看变量声明就知道除了发布智能合约会占用ram之外,为了运行wasm智能合约也是会占用大量的额外的内存。但是,个人感觉这个把内存乘以十的预计算内存的做法有点简单粗暴了,可能是为了让RAM的计算的代码不会过于复杂吧。另外,setcode_ram_bytes_multiplier这个乘数只是针对wasm虚拟机的,如果是其它虚拟机,这个值应该根据实际情况作下调整。
以上即为个人分析
网友评论