Erlang ets -- something about cache continue
上一次说到了实现一个简单cache 的基本思路和想法, http://www.cnblogs.com/--00/p/erlang_ets_something_about_cache.html 在文末, 说到了判断single record 内存占用量. 这次继续说说Erlang 数据项内存的相关问题.
在Erlang efficiency_guide 文档中, 较为清楚的表述了Erlang 系统中不同数据类型的内存消耗, 在这简单贴一两个:
Small integer | 1 word On 32-bit architectures: -134217729 < i < 134217728 (28 bits) On 64-bit architectures: -576460752303423489 < i < 576460752303423488 (60 bits) |
List | 1 word + 1 word per element + the size of each element |
Atom | 1 word. Note: an atom refers into an atom table which also consumes memory. The atom text is stored once for each unique atom in this table. The atom table is not garbage-collected. |
String (is the same as a list of integers) | 1 word + 2 words per character |
从文档中,可以看出Small integer 占用了1个字节, Atom 占用1个字节, List 占用的字节主要取决于element amount 和 size of each element .
举个栗子:
["123", "234"] 占用的内存量的计算 1 + (1 + (1 + 2 * 3)) + (1 + (1 + 2 * 3)) = 17 就是17 个字节.
Tips:
注意Atom 在Erlang 系统中只占用1 个word, 这一点对于Message 有很大的帮助.
Erlang中atom数据类型能够做的唯一的运算就是比较;在erlang中模块名和方法名都是原子;Atom用来构造Tag-Message,Atom的比较时间是常量的,与Atom的长度无关(如果拿binary做tag,比较时间是线性的);Atom就是为比较而设计,除了比较运算不要把Atom用在别的运算中.
扩展阅读参见坚强的blog.
了解了Erlang 各种数据项在Erlang 系统中的内存分配规则,那么怎么才能快速的计算呢? 有没有现成的API函数, 总不能每次都手动计算一次吧?
那就首先来看看Erlang 系统所提供的各种size:
其中对于所有数据项都通用的有:
erlang:external_size/1
,erts_debug:size/1
,erts_debug:flat_size/1
适用于二进制串有:
erlang:size/1
,erlang:byte_size/1
,erlang:bit_size/1
适用于元组的有:
erlang:size/1
,erlang:tuple_size/1
其中,比较重要的erts_debug 两个函数:
erts_debug:size/1
和erts_debug:flat_size/1
都是不在正式文档中的函数, 可以用来计算erlang数据项在内存中所需要空间. 各种数据项的空间占用可以在这里找到: http://www.erlang.org/doc/efficiency_guide/advanced.html#id68912. 这两个函数区别在于, 在具有共享内存的数据结构中,erts_debug:size/1
只计算一次共享的数据大小, 而erts_debug:flat_size/1
则会重复计算.这是erlang源代码中的例子:
%% size(Term)
%% Returns the size of Term in actual heap words. Shared subterms are
%% counted once. Example: If A = [a,b], B =[A,A] then size(B) returns 8,
%% while flat_size(B) returns 12.
文档中有另外一个例子: http://www.erlang.org/doc/efficiency_guide/processes.html
总的来说,
erts_debug:size/1
是erlang数据项在内存中所占用的空间大小,erts_debug:flat_size/1
是同一节点内, 跨进程移动数据项(包括ETS操作)所需要拷贝的数据大小.
OK, 先做个简单的test :
$ cat test_for_ets_record_flat_size.erl
-module(test_for_ets_record_flat_size). -compile(export_all). start() ->
A = ets:new(a, [named_table, public]),
D = {[{} || _ <- lists:seq(, )], [self() || _ <- lists:seq(, )], [{<<"">>, {}} || _ <- lists:seq(, )]},
io:format(" ** data words size ~p~n", [erts_debug:flat_size(D)]),
io:format(" ** before insert ~p~n", [ets:info(A, memory)]),
ets:insert(A, D),
io:format(" ** after insert ~p~n", [ets:info(A, memory)]).
执行结果:
$ erl
Erlang/OTP [erts-6.3] [source] [-bit] [smp::] [async-threads:] [hipe] [kernel-poll:false] [dtrace] Eshell V6. (abort with ^G)
> test_for_ets_record_flat_size:start().
** data words size
** before insert
** after insert
ok
从结果来看, flat_size 的方法差了4个字节. (erts_debug:size/1 能相差 8095 个字节) 为什么?
erts_debug:size/1 只计算一次共享的数据大小, 而erts_debug:flat_size/1
则会重复计算. 但为什么erts_debug:flat_size 还是会相差4个字节呢?
带着这个疑惑去Google erlang erts_debug flat_size 找到了 Erlang-MailList :
After looking at this more I have realized the documentation of the memory information is correct as would be expected. Sorry for the noise about this. Some comment that talks about erts_debug:flat_size/1 (and erts_debug:size/1) providing the process heap size only, with an additional 1 word excluded for the register or stack storage of the top-level term would help make things clearer. This may be straight-forward for some since it makes logical sense, but I didn't know about these internal details and I wanted to be sure I was looking at the size correctly.
提到了erts_debug:flat_size ONLY 提供占用进程heap size .
回过头看 源代码:
Returns the size of Term in actual heap words.
事情进展到这, 有一点已经搞明白了: erts_debug:flat_size/1 只能计算Erlang Term 在进程heap 中占用的内存, 并不能计算所有的内存占用量.然后通过上面的Erlang-MailList 找到了github 上的这个开源项目: erlang_term
摘取其中关键性的一段代码:
byte_size_term(Term, WordSize) ->
DataSize = if
is_binary(Term) ->
BinarySize = erlang:byte_size(Term),
if
BinarySize > 64 ->
BinarySize;
true ->
% in the heap size
0
end;
true ->
0
end,
% stack/register size + heap size + data size
(1 + erts_debug:flat_size(Term)) * WordSize + DataSize.
从上面的代码可以看出, Erlang Term 的内存占用量应该是process heap 的内存占用量(通过erts_debug:flat_size/1 计算), stack 占用量以及共享内存占用量的总和.
好, 继续上test code :
$ cat test_for_ets_record.erl
-module(test_for_ets_record). -compile(export_all). start() ->
A = ets:new(a, [named_table, public]),
D = {[{} || _ <- lists:seq(, )], [self() || _ <- lists:seq(, )], [{<<"">>, {}} || _ <- lists:seq(, )]},
io:format(" ** data words size ~p~n", [erlang_term:byte_size(D)/]),
io:format(" ** before insert ~p~n", [ets:info(A, memory)]),
ets:insert(A, D),
io:format(" ** after insert ~p~n", [ets:info(A, memory)]).
测试结果:
$ erl -pa ./ebin -pa ./
Erlang/OTP [erts-6.3] [source] [-bit] [smp::] [async-threads:] [hipe] [kernel-poll:false] [dtrace] Eshell V6. (abort with ^G)
> test_for_ets_record:start().
** data words size 10325.0
** before insert
** after insert
ok
why ?? 为什么还差3个字节呢? 好吧, 只能开issues请教作者了.
So, the erlang_term module can help you manage caching, but the real situation in the Erlang VM with the many memory pools is more complex.
没辙了, 要搞清楚这3个字节在ets table 中用到了什么地方, 就需要详细了解ets 的内存管理方式.只能先暂时搁置了(待续).
总结:
1, erts_debug:flat_size/1 只计算了Erlang Term 在process heap 中的size ;
2, erlang_term is so amazing .
Erlang ets -- something about cache continue的更多相关文章
- Erlang ets -- something about cache
都说用ets 写一个cache 太简单, 那就简单的搞一个吧, 具体代码就不贴了, 就说说简要的需求和怎么做(说设计有点虚的慌). 需求场景 >> 查询系统,对于主存储而言,一次写入多次查 ...
- Erlang ETS Table
不需要显示用锁,插入和查询时间不仅快而且控制为常量,这就是Erlang的ETS Table. 为什么而设计? Erlang中可以用List表达集合数据,但是如果数据量特别大的话在List中访问元素就会 ...
- erlang ets表
一.表遍历 通过ets:first/1获取表的第一个关键字,表中下一个关键字用ets:next/2得到,直到ets:next/2返回'$end_of_table' 当多几个进程并发访问ets表时,可以 ...
- Erlang库 -- 有意思的库汇总
抄自这里 首先,库存在的目的大致可分为:1.提供便利2.尽可能解决一些痛点 首先,我们先明确一下Erlang编程语言的一些痛点(伪痛点):1,单进程问题Erlang虚拟机属于抢占式调度,抢占式调度有很 ...
- 一次erlang 节点CPU严重波动排查
新服务上线后观察到,CPU在10 ~ 70%间波动严重,但从每秒业务计数器看业务处理速度很平均. 接下来是排查步骤: 1. dstat -tam 大概每10s一个周期,网络流量开始变得很小,随后突然增 ...
- [Erlang 0126] 我们读过的Erlang论文
我在Erlang Resources 豆瓣小站上发起了一个征集活动 [链接] ,"[征集] 我们读过的Erlang论文",希望大家来参加.发起这样一个活动的目的是因为Erlang相 ...
- ubuntu安装erlang
照着园子里一篇博文安装erlang,各种错调不出来.最后发现官网有解决方案: https://www.erlang-solutions.com/downloads/download-erlang-ot ...
- Erlang/OTP 中文手册
http://erldoc.com/ Open Telecom Platform application array asn1rt base64 binary calendar code dbg di ...
- Erlang--etc结构解析
Erlang中可以用List表达集合数据,但是如果数据量特别大的话在List中访问元素就会变慢了;这种主要是由于List的绝大部分操作都是基于遍历完成的. Erlang的设计目标是软实时(参考:htt ...
随机推荐
- UVa 10791 最小公倍数的最小和(唯一分解定理)
https://vjudge.net/problem/UVA-10791 题意: 输入整数n,求至少两个正整数,使得它们的最小公倍数为n,且这些整数的和最小. 思路: 首先对n进行质因数分解,举个例子 ...
- R语言笔记-set.seed()函数
今天查了一下R语言中set.seed(),该命令的作用是设定生成随机数的种子,种子是为了让结果具有重复性.如果不设定种子,生成的随机数无法重现. set.seed()用于设定随机数种子,一个特定的种子 ...
- Phpstorm Alt+Enter 自动导入类
很方便!!!能够自动提示哪些类没有自动加载!!!然后Alt+Enter进行安装!!!
- 解决 android.support.v7.widget.GridLayout 使用 xmlns:app 出现 error 的问题
GridLayout 是在 Android API Level 14 加进来的 它可用来取代 TableLayout 也提供了自由度较大且实用的排版功能 为了兼容 4.0 以下的较低版本 Androi ...
- 排序算法总结(基于Java实现)
前言 下面会讲到一些简单的排序算法(均基于java实现),并给出实现和效率分析. 使用的基类如下: 注意:抽象函数应为public的,我就不改代码了 public abstract class Sor ...
- 2-14-2 MySQL数据类型
MySQL数据类型: 对数据进行分类,针对不同分类进行不同的处理. 1. 使系统能够根据数据类型来操作数据. 2. 预防数据运算时出错. 3. 更有效的利用空间. 数据分类,可以使用最少的存储,来存放 ...
- 向多页TABLE中插入数据时,新增行总是在当前页的最后一行
CODE IN CO OATableBean table = (OATableBean)webBean.findChildRecursive("LineTable"); int n ...
- 苹果iPhone 5C和5S发布后,消费者如何选择?
9月11日凌晨苹果新品发布会,笔者的朋友圈居然没有看直播的,真果粉太少了.笔者来阐述一些容易忽略的东西. iPhone5C和5S与5有什么不一样? 新品iPhone 5S 外观与iPhone5 相似度 ...
- 《转》深入理解Activity启动流程(二)–Activity启动相关类的类图
本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 在介绍Activity的详细启动流程之前,先为大家介绍Act ...
- 微信逆向工程之远程操作Mac
远程控制指令: (功能-指令-是否开启) macbook控制: 屏幕保护-ScreenSave-开启 锁屏-LockScreen-开启 休眠-Sleep-开启 关机-Shutdown-开启 重启-Re ...