1、memcached 介绍

1.1 memcached 是什么?

memcached 是以LiveJournal旗下Danga Interactive 公司的Brad Fitzpatric 为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal 等众多服务中提高Web

应用扩展性的重要因素。许多Web 应用都将数据保存到RDBMS 中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS 的负担加重、数据库响应恶化、网站显示延迟等重大影响。这时就该memcached 大显身手了。memcached 是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web 应用的速度、提高可扩展性。

内置内存存储方式

研究memcached这个产品,首先从它的内存模型开始:我们知道c++里分配内存有两种方式,预先分配和动态分配,显然,预先分配内存会使程序比较快,但是它的缺点是不能有效利用内存,而动态分配可以有效利用内存,但是会使程序运行效率下降,memcached的内存分配就是基于以上原理,显然为了获得更快的速度,有时候我们不得不以空间换时间。

Memcached的高性能源于两阶段哈希(two-stage hash)结构。Memcached就像一个巨大的、存储了很多<key,value>对的哈希表。通过key,可以存储或查询任意的数据。 客户端
可以把数据存储在多台memcached上。当查询数据时,客户端首先参考节点列表计算出key的哈希值(阶段一哈希),进而选中一个节点;客户端将请求发送给选中的节点,然后
memcached节点通过一个内部的哈希算法(阶段二哈希),查找真正的数据(item)并返回给客户端。从实现的角度看,memcached是一个非阻塞的、基于事件的服务器程序。

为了提高性能,memcached 中保存的数据都存储在memcached 内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached 本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题

memcached 不互相通信的分布式

memcached 尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个

memcached 不会互相通信以共享信息。那么,怎样进行分布式呢?这完全取决于客户端的实现。

2.2 memcached 启动

memcached 启动的命令在安装目录的bin 二级目录下,如/home/test/app/memcahced-1.4.2/bin/memcached -p 11222 -m 128–d

常用的一些启动选项介绍选项说明

-p 侦听的端口,默认为11211

-m 使用内存大小,默认的64m

-d 作为daemon 在后台启动

-vv 用very vrebose 模式启动,调试信息和错误输出到控制台

-l 侦听的地址,默认为所有可以访问的地址

-M 用于在内存溢出的时候,返回一个错误,禁止自动的移出数

据,替代的是返回一个error

-P Pid 文件存在的路径,仅限加上-d 参数是用

-c 最大同时的连接数,默认为1024

其它的一些选项,可以通过–h 命令来进行查看

2.3命令行访问memcached

下面假设memcached 启动时的-p 参数为11311,命令操作在启动memcached

本机首先telnet 连接到memcached 服务器

telnet 127.0.0.1 11311

telnet 成功之后,大概会显示下面的信息

Trying 127.0.0.1...

Connected to localhost.localdomain (127.0.0.1).

Escape character is '^]'.

各种状态(stats)

STAT <name> <value>\r\n

如:stats命令,则返回以下信息:

stats
STAT pid 26804
STAT uptime 182783
STAT time 1404973716
STAT version 1.4.13
STAT libevent 2.0.11-stable
STAT pointer_size 64
STAT rusage_user 2.320647
STAT rusage_system 5.411177
STAT curr_connections 34
STAT total_connections 558
STAT connection_structures 37
STAT reserved_fds 20
STAT cmd_get 127292
STAT cmd_set 60056
STAT cmd_flush 145
STAT cmd_touch 0
STAT get_hits 83811
STAT get_misses 43481
STAT delete_misses 15970
STAT delete_hits 11992
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 14300156
STAT bytes_written 11507140
STAT limit_maxbytes 134217728      #  分配给memcache的内存大小(字节)
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT expired_unfetched 16884
STAT evicted_unfetched 0
STAT bytes 609350    # 当前服务器存储items占用的字节数
STAT curr_items 4668    # 服务器当前存储的items数量
STAT total_items 60056
STAT evictions 0     # 分配给memcache的空间用满后需要删除旧的items数,踢出。
STAT reclaimed 27160  #回收再利用,已过期的数据条目来存储新数据。
END

存储命令(set ,add ,replace)

客户端会发送一行像这样的命令:

<command name> <key> <flags> <exptime> <bytes>\r\n

如:

set key1 0 600 5\r\nvalue\r\n

add key2 0 500 2\r\n

replace key1 0 600 6\r\nvalue1\r\n

详细的命令说明,可以见附录的memcached 中英文协议内容

读取命令(get)

命令如下:get <key>*\r\n

- <key>* 表示一个或多个键值,由空格隔开的字串

如:

get key1

VALUE key1 0 7

value12

删除命令(delete)

命令如:delete <key> <time>\r\n

<key> 是客户端希望服务器删除的内容的键名

- <time> 是一个单位为秒的时间(或代表直到某一刻的Unix时间),在该时间内服务器会拒绝对于此键名的“add”和“replace”命令。此时内容被放入delete队列,无法再通过“get”得到该内容,也无法是用“add”和“replace”命令(但是“set”命令可用)。直到指定时间,这些内容被最终从服务器的内存中彻底清除

<time>参数是可选的,缺省为0(表示内容会立刻清除,并且随后的存储命令均可用

如:delete key1

退出命令(quit)

如:quit

4、理解memcached 的内存存储

Memcache内存分配机制
Memcache使用了Slab Allocator的内存分配机制:按照预先规定的大小,将分配的内存分割成特定长度的块,以完全解决内存碎片问题
Memcache的存储涉及到slab,page,chunk三个概念
1.Chunk为固定大小的内存空间,默认为96Byte。
2.page对应实际的物理空间,1个page为1M。
3.同样大小的chunk又称为slab。

4.1Slab Allocation 机制:整理内存以便重复使用

最近的memcached 默认情况下采用了名为Slab Allocator 的机制分配、管理内存。在该机制出现以前,内存的分配是通过对所有记录简单地进行malloc和free 来进行的。但是,这种方式会导致内存碎片,加重操作系统内存管理器的负担,最坏的情况下,会导致操作系统比memcached 进程本身还慢。Slab Allocator 就是为解决该问题而诞生的

Slab Allocation 的原理相当简单。将分配的内存分割成各种尺寸的块

(chunk),并把尺寸相同的块分成组(chunk 的集合)

而且,slab allocator 还有重复使用已分配的内存的目的。也就是说,分配到的内存不会释放,而是重复利用。

Slab Allocation 的主要术语

Page

分配给Slab 的内存空间,默认是1MB。分配给Slab 之后根据slab 的大小切分成chunk。

Chunk

用于缓存记录的内存空间。

Slab Class

特定大小的chunk 的组

4.2 Slab中缓存记录的原理

memcached 根据收到的数据的大小,选择最适合数据大小的slab,memcached 中保存着slab 内空闲chunk 的列表,根据该列表选择chunk,然

后将数据缓存于其中

4.3 Slab Allocator 的缺点

由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100 字节的数据缓存到128 字节的chunk 中,剩余的28字节就浪费了

对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案。就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下,只要使用适合数据大小的组的列表,就可以减少浪费。但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。但是,我们可以调节slab class 的大小的差别。接下来说明growth factor 选项。

4.4 使用Growth Factor进行调优

memcached 在启动时指定Growth Factor 因子(通过f 选项),就可以在某种程度上控制slab 之间的差异。默认值为1.25。但是,在该选项出现之前,这个因子曾经固定为2,称为“powers of 2”策略。

下面是启动后的verbose 输出:

slab class 1: chunk size 128 perslab 8192

slab class 2: chunk size 256 perslab 4096

slab class 3: chunk size 512 perslab 2048

slab class 4: chunk size 1024 perslab 1024

slab class 5: chunk size 2048 perslab 512

slab class 6: chunk size 4096 perslab 256

slab class 7: chunk size 8192 perslab 128

slab class 8: chunk size 16384 perslab 64

slab class 9: chunk size 32768 perslab 32

slab class 10: chunk size 65536 perslab 16

slab class 11: chunk size 131072 perslab 8

slab class 12: chunk size 262144 perslab 4

slab class 13: chunk size 524288 perslab 2

可见,从128 字节的组开始,组的大小依次增大为原来的2 倍。这样设置的问题是,slab 之间的差别比较大,有些情况下就相当浪费内存。因此,为尽量减少内存浪费,两年前追加了growth factor 这个选项来看看现在的默认设置(f=1.25)时的输出(篇幅所限,这里只写到第10 组):

slab class 1: chunk size 88 perslab 11915

slab class 2: chunk size 112 perslab 9362

slab class 3: chunk size 144 perslab 7281

slab class 4: chunk size 184 perslab 5698

slab class 5: chunk size 232 perslab 4519

slab class 6: chunk size 296 perslab 3542

slab class 7: chunk size 376 perslab 2788

slab class 8: chunk size 472 perslab 2221

slab class 9: chunk size 592 perslab 1771

slab class 10: chunk size 744 perslab 1409

可见,组间差距比因子为2 时小得多,更适合缓存几百字节的记录。从上面的输出结果来看,可能会觉得有些计算误差,这些误差是为了保持字节数的对齐而故意设置的。将memcached 引入产品,或是直接使用默认值进行部署时,最好是重新计算一下数据的预期平均长度,调整growth factor,以获得最恰当的设置。内存是珍贵的资源,浪费就太可惜了。

item占用空间计算
*nsuffix = (uint8_t) snprintf(suffix, 40, " %d %d\r\n", flags, nbytes – 2);     return sizeof(item) + nkey + *nsuffix + nbytes;
*nsuffix=" %d %d\r\n”的长度
如果ITEM_CAS标志设置时,这里有8字节的数据
完整的item长度是键长+值长+后缀长+item结构大小(48字节) + 8
item.length=56+key.lenght+value.length+后缀长
32位机器 item结构是32字节
64位机器 itme结构是48字节
memcache存储的时候对key的长度有限制,php和C的最大长度都是250

5、memcached 删除机制

memcached 是缓存,不需要永久的保存到服务器上,本章介绍memcache 的删除机制

5.1 memcached 在数据删除方面有效的利用资源

Memcached 不会释放已经分配的内存,记录过期之后,客户端无法再看到这一条记录,其存储空间就可以利用。

Lazy Expiration

memcached 内部不会监视记录是否过期,而是在get 时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU 时间

5.2 LRU:从缓存中有效删除数据的原理

1.search->refcount == 0  && 已经过期的  删除
2.tries = 50; // 最多尝试50次    LRU队列tail 查找 search->refcount == 0  第一个 删除
3. tries = 50; // 最多尝试50次    LRU队列tail 查找search->refcount != 0 查询时间(超过3小时)的item  第一个 删除

memcached 会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为Least Recently Used(LRU)机制来分配空间。顾名思义,这是删除“最近最少使用”的记录的机制。因此,当memcached 的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。从缓存的实用角度来看,该模型十分理想。不过,有些情况下LRU 机制反倒会造成麻烦。memcached 启动时通过“M”参数可以禁止LRU,如下所示:

$ memcached -M –m 1024

启动时必须注意的是,小写的“m”选项是用来指定最大内存大小的。不指定具体数值则使用默认值64MB。

指定“M”参数启动后,内存用尽时memcached 会返回错误。话说回来,memcached 毕竟不是存储器,而是缓存,所以推荐使用LRU

6、memcached 的分布式算法

6.1memcached 的分布式

memcached 虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。memcached 的分布式,则是完全由客户端程序库实现的。这种分布式是memcached 的最大特点

memcached 的分布式是什么意思?

下面假设memcached 服务器有node1~node3 三台,应用程序要保存键名为“tokyo”、“kanagawa”、“chiba”、“saitama”、“gunma”的数据

首先向memcached 中添加“tokyo”。将“tokyo”传给客户端程序库后,客户端实现的算法就会根据“键”来决定保存数据的memcached 服务器。服务器选定后,即命令它保存“tokyo”及其值

同样,“kanagawa”、“chiba”、“saitama”、“gunma”都是先选择服务器再保接下来获取保存的数据。获取时也要将要获取的键“tokyo”传递给函数库。函数库通过与数据保存时相同的算法,根据“键”选择服务器。使用的算法相同,就能选中与保存时相同的服务器,然后发送get 命令。只要数据没有因为某些原因被删除,就能获得保存的值。

这样,将不同的键保存到不同的服务器上,就实现了memcached 的分布式。memcached 服务器增多后,键就会分散,即使一台memcached 服务器发生故障无法连接,也不会影响其他的缓存,系统依然能继续运行

6.2 余数分布式算法

就是“根据服务器台数的余数进行分散”。求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器

余数算法的缺点

余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中。

6.3Consistent Hashing(一致哈希)

知识补充:哈希算法,即散列函数。将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。一般用于快速查找和加密算法。(常见的有MD5,SHA-1)

Consistent Hashing 的简单说明

Consistent Hashing 如下所示:首先求出memcached 服务器(节点)的哈希值,并将其配置到0~232 的圆(continuum)上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232 仍然找不到服务器,就会保存到第一台memcached 服务器上。

从上图的状态中添加一台memcached 服务器。余数分布式算法由于保存键的服务器会发生巨大变化,而影响缓存的命中率,但Consistent Hashing中,只有在continuum 上增加服务器的地点逆时针方向的第一台服务器上的键会受到影响

Consistent Hashing:添加服务器

因此,Consistent Hashing 最大限度地抑制了键的重新分布。而且,有的Consistent Hashing 的实现方法还采用了虚拟节点的思想。使用一般的hash函数的话,服务器的映射地点的分布非常不均匀。因此,使用虚拟节点的思想,为每个物理节点(服务器)在continuum上分配100~200 个点。这样就能抑制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。

通过上文中介绍的使用Consistent Hashing 算法的memcached 客户端函数库进行测试的结果是,由服务器台数(n)和增加的服务器台数(m)计算增加服务器后的命中率计算公式如下:

(1 n/(n+m)) * 100

存储命令

<command name> <key> <flags> <exptime> <bytes>\r\n

- <command name> 是set, add,或者repalce

- <key> 是接下来的客户端所要求储存的数据的键值

- <flags> 是在取回内容时,与数据和发送块一同保存服务器上的任意16位无符号整形(用十进制来书写)。客户端可以用它作为“位域”来存储一些特定的信息;它对服务器是不透明的。

- <exptime> 是终止时间。如果为0,该项永不过期(虽然它可能被删除,以便为其他缓存项目腾出位置)。如果非0(Unix 时间戳或当前时刻的秒偏移),到达终止时间后,客户端无法再获得这项内容。

- <bytes> 是随后的数据区块的字节长度,不包括用于分野的“\r\n”。它可以是0(这时后面跟随一个空的数据区块)。

- <data block> 是大段的8位数据,其长度由前面的命令行中的<bytes>指定。

• set 意思是“储存此数据”

• add 意思是“储存此数据,只在服务器*未*保留此键值的数据时”

• replace 意思是“储存此数据,只在服务器*曾*保留此键值的数据时”

发送命令行和数据区块以后,客户端等待回复,可能的回复如下:

- "STORED\r\n"表明成功.

- "NOT_STORED\r\n"表明数据没有被存储,但不是因为发生错误。这通常意味着add或replace 命令的条件不成立,或者,项目已经位列删除队列(参考后文的“delete”命令)。

取回命令

get <key>*\r\n

- <key>* 表示一个或多个键值,由空格隔开的字串这行命令以后,客户端的等待0个或多个项目,每项都会收到一行文本,然后跟着数据区块。所有项目传送完毕后,服务器发送以下字串:"END\r\n"来指示回应完毕,服务器用以下形式发送每项内容:

VALUE <key> <flags> <bytes>\r\n

<data block>\r\n

- <key> 是所发送的键名

- <flags> 是存储命令所设置的记号

- <bytes> 是随后数据块的长度,*不包括* 它的界定符“\r\n”

- <data block> 是发送的数据

如果在取回请求中发送了一些键名,而服务器没有送回项目列表,这意味着服务器没这些键名(可能因为它们从未被存储,或者为给其他内容腾出空间而被删除,或者到期,或者被已客户端删除)。

删除

delete <key> <time>\r\n

- <key> 是客户端希望服务器删除的内容的键名

- <time> 是一个单位为秒的时间(或代表直到某一刻的Unix时间),在该时间内服务器会拒绝对于此键名的“add”和“replace”命令。此时内容被放入delete队列,无法再通过“get”得到该内容,也无法是用“add”和“replace”命令(但是“set”命令可用)。直到指定时间,这些内容被最终从服务器的内存中彻底清除。<time>参数是可选的,缺省为0(表示内容会立刻清除,并且随后的存储命令均可用)。

此命令有一行回应:- "DELETED\r\n"表示执行成功

- "NOT_FOUND\r\n"表示没有找到这项内容

增加/减少

命令“incr”和“decr”被用来修改数据,当一些内容需要替换、增加或减少时。这些数据必须是十进制的32位无符号整新。如果不是,则当作0 来处理。修改的内容必须存在,当使用“incr”/“decr”命令修改不存在的内容时,不会被当作0处理,而是操作失败。

客户端发送命令行:

incr <key> <value>\r\n或decr <key> <value>\r\n

- <key> 是客户端希望修改的内容的建名

- <value> 是客户端要增加/减少的总数。

回复为以下集中情形:

- "NOT_FOUND\r\n"指示该项内容的值,不存在。

- <value>\r\n ,<value>是增加/减少。

注意"decr"命令发生下溢:如果客户端尝试减少的结果小于0 时,结果会是0。"incr" 命令不会发生溢出。

状态

命令"stats" 被用于查询服务器的运行状态和其他内部数据。有两种格式。不带参数的:

stats\r\n

这会在随后输出各项状态、设定值和文档。另一种格式带有一些参数:

stats <args>\r\n

通过<args>,服务器传回各种内部数据。因为随时可能发生变动,本文不提供参数的种类及其传回数据。

各种状态

受到无参数的"stats"命令后,服务器发送多行内容,如下:

STAT <name> <value>\r\n

服务器用以下一行来终止这个清单:END\r\n,在每行状态中,<name> 是状态的名字,<value>使状态的数据。以下清单,是所有的状态名称,数据类型,和数据代表的含义。

在“类型”一列中,"32u"表示32 位无符号整型,"64u"表示64 位无符号整型,"32u:32u"表示用冒号隔开的两个32 位无符号整型。

名称

类型

含义

pid

32u

服务器进程ID

uptime

32u

服务器运行时间,单位秒

time

32u

服务器当前的UNIX时间

version

string

服务器的版本号

rusage_user

32u

该进程累计的用户时间(秒:微妙)

rusage_system

32u

该进程累计的系统时间(秒:微妙)

curr_items

32u

服务器当前存储的内容数量

total_items

32u

服务器启动以来存储过的内容总数

bytes

64u

服务器当前存储内容所占用的字节数

curr_connections

32u

连接数

total_connections

32u

服务器运行以来接受的连接总数

connection_structures

32u

服务器分配的连接结构的数量

cmd_get

32u

取回请求总数

cmd_set

32u

存储请求总数

get_hits

32u

请求成功的总次数

get_misses

32u

请求失败的总次数

bytes_read

64u

服务器从网络读取到的总字节数

bytes_written

64u

服务器向网络发送的总字节数

limit_maxbytes

32u

服务器在存储时被允许使用的字节总数

如果不想每次通过输入stats来查看memcache状态,可以通过echo "stats" |nc  ip port 来查看,例如:echo "stats" | nc 127.0.0.1 9023。

7.Memcache 命中率
缓存命中率 = get_hits/cmd_get * 100% (总命中次数/总请求次数)

要提高memcached的命中率,预估我们的value大小并且适当的调整内存页大小和增长因子是必须的。

命中率的提升可以通过多种方案实现.
其一,提高服务获取的内存总量
其二,提高空间利用率,这实际上也是另一种方式的增加内存总量
其三,应用一级别上再来一次LRU
其四,对于整体命中率,可以采取有效的冗余策略,减少分布式服务时某个server发生服务抖动的情况

8.一些注意
1. memcache已经分配的内存不会再主动清理。
2. memcache分配给某个slab的内存页不能再分配给其他slab。
3. flush_all不能重置memcache分配内存页的格局,只是给所有的item置为过期。
4. memcache最大存储的item(key+value)大小限制为1M,这由page大小1M限制
5.由于memcache的分布式是客户端程序通过hash算法得到的key取模来实现,不同的语言可能会采用不同的hash算法,同样的客户端程序也有可能使用相异的方法,因此在多语言、多模块共用同一组memcached服务时,一定要注意在客户端选择相同的hash算法
6.启动memcached时可以通过-M参数禁止LRU替换,在内存用尽时add和set会返回失败
7.memcached启动时指定的是数据存储量,没有包括本身占用的内存、以及为了保存数据而设置的管理空间。因此它占用的内存量会多于启动时指定的内存分配量,这点需要注意。
8.memcache存储的时候对key的长度有限制,php和C的最大长度都是250

Memcache技术分享:介绍、使用、存储、算法、优化、命中率的更多相关文章

  1. 【华为云技术分享】智能诊断和优化,华为云DAS服务云DBA平台让您无忧运维

    摘要:随着时代的发展,传统的“人工”运维方式,已经逐渐跟不上企业业务发展的需要.如何更好的保证数据库系统的稳定性.安全性.完整性和高性能,实现运维工具化.产品化.自助化.自动化,是当前数据管理和运维面 ...

  2. 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

    1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...

  3. 美团技术分享:深度解密美团的分布式ID生成算法

    本文来自美团技术团队“照东”的分享,原题<Leaf——美团点评分布式ID生成系统>,收录时有勘误.修订并重新排版,感谢原作者的分享. 1.引言 鉴于IM系统中聊天消息ID生成算法和生成策略 ...

  4. 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

    本文由爱奇艺技术团队原创分享,原题<爱奇艺Android客户端启动优化与分析>. 1.引言 互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对Andro ...

  5. 腾讯技术分享:Android版手机QQ的缓存监控与优化实践

    本文内容整理自公众号腾讯Bugly,感谢原作者的分享. 1.问题背景 对于Android应用来说,内存向来是比较重要的性能指标.内存占用过高,会影响应用的流畅度,甚至引发OOM,非常影响用户体验.因此 ...

  6. 大型网站优化-memcache技术

    大型网站优化-memcache技术 memory+cache 内存缓存 memcache简介 memcache是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发 ...

  7. iOS开发技术分享(1)— iOS本地数据存储

    iOS开发技术分享(1)— iOS本地数据存储 前言: 我本是一名asp.net程序员,后来加入了iOS游戏开发队伍,到现在也有一年多的时间了.这一年来,每天都干到2.3点钟才睡觉,不为别的,只为了学 ...

  8. Cocos2d-x手游技术分享(1)-【天天打蚊子】数据存储与音效篇

    前言: 手游项目<天天打蚊子>终于上线,特地写几篇技术分享文章,分享一下其中使用到的技术,其中使用cocos2d-x引擎,首选平台iOS,也请有iPhone或者iPad的朋友帮忙下载好评. ...

  9. 技术分享 | 在MySQL对于批量更新操作的一种优化方式

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 作者:景云丽.卢浩.宋源栋 GreatSQL社区原创内容未经授权不得随意使用,转 ...

随机推荐

  1. java程序员必须会的技能

    1.语法:必须比较熟悉,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道任何修正. 2.命令:必须熟悉JDK带的一些常用命令及其常用选项,命令至少需要熟悉:a ...

  2. iOS经典面试题

    前言 写这篇文章的目的是因为前两天同学想应聘iOS开发,从网上找了iOS面试题和答案让我帮忙看看.我扫了一眼,倒吸了一口冷气,仔细一看,气的发抖.整篇题目30多个没有一个答案是对的,总结这篇面试题的作 ...

  3. Hark的数据结构与算法练习之珠排序

    ---恢复内容开始--- 算法说明 珠排序是分布排序的一种. 说实在的,这个排序看起来特别的巧妙,同时也特别好理解,不过不太容易写成代码,哈哈. 这里其实分析的特别好了,我就不画蛇添足啦.  大家看一 ...

  4. hdu 5753 Permutation Bo

    这里是一个比较简单的问题:考虑每个数对和的贡献.先考虑数列两端的值,两端的摆放的值总计有2种,比如左端:0,大,小:0,小,大:有1/2的贡献度.右端同理. 中间的书总计有6种可能.小,中,大.其中有 ...

  5. subList和asList

    subList subList返回仅仅只是一个视图.直接上源码 public List<E> subList(int fromIndex, int toIndex) { subListRa ...

  6. AppleWatch开发教程之调试程序使用帮助文档

    AppleWatch开发教程之调试程序使用帮助文档 AppleWatch开发教程之调试程序 调试又被称为排错,是发现和减少程序错误的一个过程.在Xcode中进行调试的需要实现以下几个步骤: 1.添加断 ...

  7. jQuery对表单、表格的操作及更多应用(下:其他应用)

    内容摘录自锋利的JQuery一书 三.其他应用  1 网页字体大小控制(P164) <span class="bigger">放大</span> <s ...

  8. POJ3162 Walking Race(树形DP+尺取法+单调队列)

    题目大概是给一棵n个结点边带权的树,记结点i到其他结点最远距离为d[i],问d数组构成的这个序列中满足其中最大值与最小值的差不超过m的连续子序列最长是多长. 各个结点到其他结点的最远距离可以用树形DP ...

  9. c/c++ 笔试面试题

    #include <iostream> using namespace std; class A { public: void sayHi(){ cout<<"hel ...

  10. 有关g++编译调试的问题

    打了个指针版的treap,想用gdb调试,用gcc -g ×××.cpp -o a 时却报错了——直接用gcc编译却不会报错,提示:对‘operator new(unsigned int)’未定义的引 ...