Redis源码分析(十一)--- memtest内存检测

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

今天我们继续redis源码test测试包下的其他文件,今天看完的是memtest文件,翻译器起来,就是memory test 内存检测的意思,这个文件虽然说代码量不是很多,但是里面的提及了很多东西,也给我涨了很多见识,网上关于memtest这种类似的redis内部边缘的文件解析基本没有,所以自己从头开始学习。机器的内存检测会和机器的CPU位数有关,32位或64位会影响后面的一些宏定义参数。首先亮出memtest中的API:

  1. /* 内存检测API */  
  2. void memtest_progress_start(char *title, int pass) /* 内存检测加载开始,输出开始的一些图线显示 */  
  3. void memtest_progress_end(void) /* progress bar加载完再次清屏操作 */  
  4. void memtest_progress_step(size_t curr, size_t size, char c) /* progress填充自己设置的字符串 */  
  5. void memtest_addressing(unsigned long *l, size_t bytes) /* 地址检测方法 */  
  6. void memtest_fill_random(unsigned long *l, size_t bytes) /* 随机填充内存 */  
  7. void memtest_fill_value(unsigned long *l, size_t bytes, unsigned long v1, unsigned long v2, char sym) /* 像上面的方法,只不过这是特定2种值的填充v1,v2 */  
  8. void memtest_compare(unsigned long *l, size_t bytes) /* 内存比较方法 */  
  9. void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int times) /* 进行多次内存compare比较操作 */  
  10. void memtest_test(size_t megabytes, int passes) /* 整个内存检测类操作的测试方法,passes为目标的循环数 */  
  11. void memtest_non_destructive_invert(void *addr, size_t size) /* 将内存地址,进行了按位取反操作,不具有对数据的破坏性 */  
  12. void memtest_non_destructive_swap(void *addr, size_t size) /* 将内存地址,2个,2个内部之间做交换,同样不对数据具有破坏性 */  
  13. void memtest(size_t megabytes, int passes) /* 开发给整个系统使用的内存检测方法 */  
复制代码

里面主要的方法就几个,每当一个内存检测的开始,都会出现progress bar的图线输出:
  1. /* 内存检测加载开始,输出开始的一些图线显示 */  
  2. void memtest_progress_start(char *title, int pass) {  
  3.     int j;  
  4.       
  5.     /*这里其实包含2个命令,"\xlb[H","xlb[2j",后面的命令是主要的操作 
  6.      *"\x1b" 是ESC的16进制ASCII码值,这里也可经表示成八进制的\033, 
  7.      *[是一个CSI(Control sequence introducer),转义序列的作用由最后一个字符决定的, 
  8.      *这里J表示删除,默认情况下它删除从当前光标处到行尾的内容, 
  9.      *这里的2为参数,它表示删除所有的显示内容。也可以使用printf "\x1b[2J"。*/  
  10.     //现定位home最开始的位置,然后实现请屏幕操作  
  11.     printf("\x1b[H\x1b[2J");    /* Cursor home, clear screen. */  
  12.           
  13.     /* Fill with dots. */  
  14.     /* 输出.符号填充屏幕 */  
  15.     for (j = 0; j < ws.ws_col*(ws.ws_row-2); j++) printf(".");  
  16.     printf("Please keep the test running several minutes per GB of memory.\n");  
  17.     printf("Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/");  
  18.     //最后一个参数变了,为K,意义也不一样了变成删除当前行操作  
  19.     printf("\x1b[H\x1b[2K");          /* Cursor home, clear current line.  */  
  20.     printf("%s [%d]\n", title, pass); /* Print title. */  
  21.     progress_printed = 0;  
  22.     //求出填满progress bar所需点的个数  
  23.     progress_full = ws.ws_col*(ws.ws_row-3);  
  24.     fflush(stdout);  
  25. }  
复制代码

我在里面解释了一下清屏操作的,printf输出形式。内存地址有效性的核心方法;
  1. /* Test that addressing is fine. Every location is populated with its own 
  2. * address, and finally verified. This test is very fast but may detect 
  3. * ASAP big issues with the memory subsystem. */  
  4. /* 此方法是测试内存地址是否有效,此种检测的速度是非常快的,但可能会检测出ASAP的巨大问题 */  
  5. /* ASAP网上查了下:(可能为)Automated Statistical Analysis Programme 自动统计分析程序 */  
  6. void memtest_addressing(unsigned long *l, size_t bytes) {  
  7.     //算出地址的长度  
  8.     unsigned long words = bytes/sizeof(unsigned long);  
  9.     unsigned long j, *p;  
  10.   
  11.     /* Fill */  
  12.     p = l;  
  13.     for (j = 0; j < words; j++) {  
  14.         //将(unsigned long)p强制类型转换到此时的*p,后面以此来判断,没有转换成功,说明存在内存地址的问题  
  15.         *p = (unsigned long)p;  
  16.         p++;  
  17.         //用A字符填充部分progress bar  
  18.         if ((j & 0xffff) == 0) memtest_progress_step(j,words*2,'A');  
  19.     }  
  20.     /* Test */  
  21.     p = l;  
  22.     for (j = 0; j < words; j++) {  
  23.         //比较Address的关键在于  
  24.         if (*p != (unsigned long)p) {  
  25.             printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n",  
  26.                 (void*) p, *p);  
  27.             exit(1);  
  28.         }  
  29.         p++;  
  30.         if ((j & 0xffff) == 0) memtest_progress_step(j+words,words*2,'A');  
  31.     }  
  32. }  
复制代码

为什么这样的方法去检测,本人也是带着比较疑惑的感觉。在内存检测中,内存地址有效性的检查只是其中的一个方法,还有一个是内存地址的填充测试,分为随机填充,和给定值的填充。下面给出随机填充的方法实现:
  1. /* Fill words stepping a single page at every write, so we continue to 
  2. * touch all the pages in the smallest amount of time reducing the 
  3. * effectiveness of caches, and making it hard for the OS to transfer 
  4. * pages on the swap. */  
  5. /* 在每次写操作的时候,在单页上填满整个字符,这样可以做到最快速的触及所有的页面 */  
  6. /* 减少了低效率的缓存使用,但是会让分区在转移页面时会比较困难 */  
  7. /* 随机填充内存 */  
  8. void memtest_fill_random(unsigned long *l, size_t bytes) {  
  9.     unsigned long step = 4096/sizeof(unsigned long);  
  10.     unsigned long words = bytes/sizeof(unsigned long)/2;  
  11.     unsigned long iwords = words/step;  /* words per iteration */  
  12.     unsigned long off, w, *l1, *l2;  
  13.   
  14.     assert((bytes & 4095) == 0);  
  15.     for (off = 0; off < step; off++) {  
  16.         l1 = l+off;  
  17.         l2 = l1+words;  
  18.         for (w = 0; w < iwords; w++) {  
  19.             //下面的rand()达到了随机存储的目的  
  20. #ifdef MEMTEST_32BIT  
  21.             *l1 = *l2 = ((unsigned long)     (rand()&0xffff)) |  
  22.                         (((unsigned long)    (rand()&0xffff)) << 16);  
  23. #else  
  24.             *l1 = *l2 = ((unsigned long)     (rand()&0xffff)) |  
  25.                         (((unsigned long)    (rand()&0xffff)) << 16) |  
  26.                         (((unsigned long)    (rand()&0xffff)) << 32) |  
  27.                         (((unsigned long)    (rand()&0xffff)) << 48);  
  28. #endif  
  29.             l1 += step;  
  30.             l2 += step;  
  31.             if ((w & 0xffff) == 0)  
  32.                 memtest_progress_step(w+iwords*off,words,'R');  
  33.         }  
  34.     }  
  35. }  
复制代码

填充内存的好处是访问页面速度更快,不会出现断断续续的内存片,但是做页面交换的时候,由于没有空间,效率恐怕会比较低下。给定数值的填充与上面的类似,不展开说了。那么,内存测试程序到底是测哪些东西的呢,也就是说,他这个文件开放给外部的一个最直接的test方法是什么呢?
  1. /* 整个内存检测类操作的测试方法,passes为目标的循环数 */  
  2. void memtest_test(size_t megabytes, int passes) {  
  3.     size_t bytes = megabytes*1024*1024;  
  4.     unsigned long *m = malloc(bytes);  
  5.     int pass = 0;  
  6.   
  7.     if (m == NULL) {  
  8.         fprintf(stderr,"Unable to allocate %zu megabytes: %s",  
  9.             megabytes, strerror(errno));  
  10.         exit(1);  
  11.     }  
  12.       
  13.     //必须经过passes论循环测试  
  14.     while (pass != passes) {  
  15.         pass++;  
  16.   
  17.         //地址检测  
  18.         memtest_progress_start("Addressing test",pass);  
  19.         memtest_addressing(m,bytes);  
  20.         memtest_progress_end();  
  21.   
  22.         //随机填充检测  
  23.         memtest_progress_start("Random fill",pass);  
  24.         memtest_fill_random(m,bytes);  
  25.         memtest_progress_end();  
  26.         //填充后比较四次  
  27.         memtest_compare_times(m,bytes,pass,4);  
  28.   
  29.         //给定数值填充,这里称为Solid fill固态填充  
  30.         memtest_progress_start("Solid fill",pass);  
  31.         memtest_fill_value(m,bytes,0,(unsigned long)-1,'S');  
  32.         memtest_progress_end();  
  33.         //填充后比较四次  
  34.         memtest_compare_times(m,bytes,pass,4);  
  35.           
  36.         //也是属于给定数值填充,这里叫Checkerboard fill键盘填充  
  37.         memtest_progress_start("Checkerboard fill",pass);  
  38.         memtest_fill_value(m,bytes,ULONG_ONEZERO,ULONG_ZEROONE,'C');  
  39.         memtest_progress_end();  
  40.         //填充后比较四次  
  41.         memtest_compare_times(m,bytes,pass,4);  
  42.     }  
  43.     free(m);  
  44. }  
复制代码

可以看见,分为4中情况,1内存地址测试,2,3,4都为填充测试,分为3种类型的填充Random fill, Solid fill, Checkboard fill 。填充之后再做内存比较,这里的内存比较是在内存内部做前半部分的内存和后半部分的内存比较操作。在memtest文件的最后,提到了一个这样的方法:
  1. /* 开发给整个系统使用的内存检测方法 */  
  2. void memtest(size_t megabytes, int passes) {  
  3.     if (ioctl(1, TIOCGWINSZ, &ws) == -1) {  
  4.         ws.ws_col = 80;  
  5.         ws.ws_row = 20;  
  6.     }  
  7.     memtest_test(megabytes,passes);  
  8.     printf("\nYour memory passed this test.\n");  
  9.     printf("Please if you are still in doubt use the following two tools:\n");  
  10.     printf("1) memtest86: http://www.memtest86.com/\n");  
  11.     printf("2) memtester: http://pyropus.ca/software/memtester/\n");  
  12.     exit(0);  
  13. }  
复制代码

这里提到了memtester和memtest86,上网查了一下,大体如下:

* * memtest和memtest86是2款内存检测软件 
* memtest不但可以彻底的检测出内存的稳定度,还可同时测试记忆的储存与检索数据的能力,让你可以确实掌控到目前你机器上正在使用的内存到底可不可信赖。 
* MemTest是一个绿色软件,直接点击执行文件即可运行 
* memtest86这是一款小巧而专业的内存测试程序,是在著名的内存测试软件Memtest86基础上开发的。 
* Memtest86+的安装和使用和其它内存测试软件有些不同,因为他不能在Windows下运行。
* 不过还是有四种方式可以运行此程序,分别为ISO引导盘、Linux下使用的bin文件、
* USB启动盘使用的EXE文件和软盘引导制作包。由于Memtest86+测试耗时较长,因此它不仅可以用于内存测试,还可以用于系统稳定性测试。Memtest86+测试完毕后,
* 按下“Esc”键退出并重新启动系统。






本文作者:HarLock
本文来自云栖社区合作伙伴rediscn,了解相关信息可以关注redis.cn网站。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
缓存 监控 Python
在Python中,如何检测和处理内存泄漏?
【2月更文挑战第7天】【2月更文挑战第18篇】在Python中,如何检测和处理内存泄漏?
|
30天前
|
IDE Linux 开发工具
内存泄漏检测工具Valgrind:C++代码问题检测的利器(一)
内存泄漏检测工具Valgrind:C++代码问题检测的利器
65 0
|
11天前
|
NoSQL 安全 Redis
redis内存限制与淘汰策略
Redis内存管理包括限制和淘汰策略。`maxmemory`配置参数决定内存上限,无设置时64位系统默认不限制,可能导致系统资源耗尽,生产环境建议设定合理值。当内存满时,未设置淘汰策略会导致写入错误。Redis提供8种淘汰策略,如LRU(最近最少使用)和LFU(最不经常使用),以及随机或基于过期时间的删除。需根据数据重要性、访问频率和一致性选择合适策略。
13 0
|
16天前
|
存储 缓存 NoSQL
Redis 服务器指南:高性能内存数据库的完整使用指南
Redis 服务器指南:高性能内存数据库的完整使用指南
|
18天前
|
存储 缓存 NoSQL
Redis的内存淘汰策略是什么?
【4月更文挑战第2天】Redis内存淘汰策略在内存满时,通过删除旧数据为新数据腾空间。策略包括:volatile-lru/LFU(基于LRU/LFU算法淘汰有过期时间的键),volatile-random/ttl(随机/按TTL淘汰),allkeys-lru/LFU(所有键的LRU/LFU),allkeys-random(随机淘汰所有键),以及noeviction(不淘汰,返回错误)。选择策略要考虑访问模式、数据重要性和性能需求。
|
26天前
|
缓存 Linux iOS开发
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
62 1
|
30天前
|
缓存 测试技术 开发工具
内存泄漏检测工具Valgrind:C++代码问题检测的利器(二)
内存泄漏检测工具Valgrind:C++代码问题检测的利器
35 0
|
1月前
|
NoSQL 应用服务中间件 Linux
Redis的内存回收机制
Redis的内存回收机制
25 2
|
1月前
|
Python
在Python中,如何检测和修复内存泄漏?
在Python中,如何检测和修复内存泄漏?
82 0
|
2月前
|
存储 缓存 NoSQL
内存淘金术:Redis 内存满了怎么办?
内存淘金术:Redis 内存满了怎么办?
35 1

热门文章

最新文章