可回收空间的分类
垃圾回收的目的是再利用(回收后的空间大小能写入有效的node),如果再利用的价值越低,其回收的必要性越低。为了进行有效的垃圾回收,UBIFS对可回收空间做了2个层次的水线划分:
死空间水线,即最小node大小(一般是最小的data node):dead_wm = ALIGN(MIN_WRITE_SZ, min_io_size);
暗空间水线,即最大node大小(一般是最大的inode node):dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, min_io_size);
一般来说, min_io_size(page or subpage) <= dead_wm <= dark_wm。在我们的系统上,dead_wm和dark_wm的水线都是一个page的大小(8K)
free + dirty < dead_wm时,此时认为垃圾很少,一般就认为此LEB full,不值得进行垃圾回收。
free + dirty < dark_wm时,因为可回收的空间较小,dark_wm被回收的概率也变小。同时为了效率和节约空间考虑,这种leb也不会被加入到内存LPT树中。如果可回收空间小于dark_wm,这段空间的回收价值就不大。所以也得出一个结论:node越大,浪费的空间越大。
可回收对象的分类
因为index node和非index node的管理方式不一样,垃圾回收需要对这2类对象进行区分处理。
非index node的管理方式为 wbuf - flash 2层结构,比较简单。在ubifs_garbage_collect_leb(BG GC)或者ubifs_gc_start_commit(Commit GC第一阶段)阶段unmap LEB完成回收;
index node的管理方式为 TNC - journal - flash 4层结构,相对复杂。在ubifs_garbage_collect_leb(BG GC)或者ubifs_gc_start_commit(Commit GC第一阶段)阶段完成准备,在ubifs_gc_end_commit (Commit GC第二阶段)阶段unmap LEB完成回收,所有被垃圾回收的index leb加入到链表idx_gc中,这个链表中的leb在ubifs_gc_end_commit阶段unmap。
垃圾回收(后台进程阶段)
后台垃圾回收由background线程负责,由wbuf定时器定时唤醒,并判断是否需要进行垃圾回收,如是,启动垃圾回收操作。正常情况下,每次垃圾回收操作回收UBIFS_GC_ONCE(5)个LEB。
回收的leb最后被unmap,并且标记为空(bud->start 设置为 0),再次使用时,会重新map。LEB unmap-map重新映射流程,UBI根据磨损均衡算法进行重新map,达到PEB磨损平衡的效果。同时也避免了反复使用一个PEB的情况。
垃圾回收时垃圾LEB上有效的数据会搬运到gc wbuf->lnum对于的LEB上,gc_lnum作为后备的垃圾回收目的LEB,如果gc的wbuf->lnum无效,取gc_lnum作为gc wbuf->lnum,并置c->gc_lnum无效(switch_gc_head)。通过gc_lnum,保证在垃圾回收时,不会出现找不到搬运目的LEB的情况(即gc wbuf->lnum)。
垃圾回收判断准则:
检查gc水线设置gc_waterline, 只有当总的脏空间lst.total_dirty > 分卷总大小/gc_waterline时,才进行GC,避免在空闲空间较多的情况下进行gc。gc_waterline默认为UBIFS_FREE_RESERVE_RATIO(5)。
而且,对于index node,ubifs对于index的回收是只回收脏空间大于一半擦除块的,其他index擦除块可能即使有脏空间也不会进行回收。
垃圾回收流程:
1)判断是否需要commit,如是,返回-EAGAIN,触发commit流程
2)已经回收了index LEB并且gc已连续尝试SOFT_LEBS_LIMIT(4)次,返回-EAGAIN
3)如果gc已连续尝试HARD_LEBS_LIMIT(32)次,返回-ENOSPC
4)查找dirty LEB进行回收(查找顺序依次是lpt_heap[LPROPS_DIRTY_IDX], lpt_heap[LPROPS_DIRTY], lpt_heap[LPROPS_FREE],c->uncat_list,LPT in flash)
5)读取dirty LEB的node,并进行排序、分类、丢弃过时数据和无需搬运数据等处理
6)搬运数据到gc wbuf对应的LEB(gc LEB),回收垃圾LEB,这里区分index LEB和非index LEB详细流程见下
7)如果回收的是非index LEB,此次GC结束
8)如果回收的是index LEB,继续GC
9)已经回收过多次还没有回收成功,说明每次回收的块都用于gc自己(因为GC需要始终占用一块free的LEB,用来作为搬运的目地LEB,即gc LEB),而且当前用于gc回收的leb空间没有更多。这里就尝试找更脏的leb,因为这样的LEB上的有效数据少,回收这样的leb需要的空间就要小些。
10)同步gc wbuf,unmap gc LEB(c->gc_lnum)
11)更新LPT树
搬运数据,回收LEB详细流程:
可全部回收的 leb(free + dirty == leb_size):sync,然后unmap
1)如果不是全free的leb,将data和index wbuf写到对应的flash LEB。避免GC后,wbuf又把obsoleting nodes写入flash。然后再更新LEB lprops并将此LEB加入到c->frdi_idx_list(index LEB)或c->freeable_list(data LEB)。
2)unmap回收LEB
3)如果c->gc_lnum无效,将回收的lnum作为c->gc_lnum,然后返回LEB_RETAINED。否则返回LEB_FREED。
非index leb:搬运后再sync,然后unmap
1)将有效node搬运到GC LEB的wbuf(c->jheads[GCHD].wbuf)
2)为了保证垃圾回收的节点是存在flash的,同步data和index LEB的wbuf到flash。避免GC后,wbuf又把obsoleting nodes写入flash
3)更新LEB lprops并将此LEB加入到c->freeable_list(data LEB)
4)如果c->gc_lnum无效,将回收的lnum作为c->gc_lnum,然后返回LEB_RETAINED。否则,同步gc LEB的wbuf到flash,再unmap回收LEB,然后返回LEB_FREED。
index leb:更新idx_gc->list对象和c->frdi_idx_list对象,以备在end commit gc阶段使用
1)遍历index leb中index node,将 index node加入到TNC,并将TNC中该节点对应路径设置为脏,commit的时候就会重新写入flash,在gc中就达到了搬运的目的;
2)将此LEB加入到已经gc的index链表中 idx_gc->list。因为已经将这个index leb读取到TNC中,所以在下一次commit的时候会将这些读取到TNC中的index写入flash。但是不能立即unmap这个leb,因为commit还没有发生, 如果发生掉电,还需要保留这个index leb,用于恢复,否则发生掉电,这个index leb已经unmap,但又没有commit完成,则这个index leb上的数据就会丢失。
3)更新LEB lprops并将此LEB加入到c->frdi_idx_list(index LEB),然后返回LEB_FREED_IDX。
垃圾回收(提交阶段)
提交阶段的垃圾回收,以commit为界,划分为2部分:ubifs_gc_start_commit和ubifs_gc_end_commit。
ubifs_gc_start_commit:更新idx_gc->list对象和c->frdi_idx_list对象,以备在end commit gc阶段使用
1)unmap freeable_list LEB,更新lprops;
2)找出所有的frdi_idx_list LEB,并更新到idx_gc中;
ubifs_gc_end_commit:unmap idx_gc LEB
此阶段前,已完成commit,所以可以放心地unmap所有的idx_gc LEB;
至此,UBIFS文件系统垃圾回收流程完成。
--EOF--
- JVM学习总结二——垃圾回收算法
昨天总结了JVM内存分区相关的知识,这次我们将来了解下JVM的另一个核心知识点——垃圾回收算法.这一部分其实并不太难,如果对操作系统的内存处理算法有所了解,那么这部分算法其实只看名字就能明白,两者在原 ...
- 再谈kbmMW垃圾回收
很早就写了关于kbmMW Server如何实现的垃圾回收,但最近一段时间还是为此遇到问题,实现的Server不能稳定运行,发生问题后不响应客户端的查询请求,在客户端得到服务端返回地址错误信息,只能重启 ...
- 深入Java核心 探秘Java垃圾回收机制(转自http://edu.21cn.com/java/g_189_859836-1.htm)
垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机 ...
- Java Garbage Collection基础详解------Java 垃圾回收机制技术详解
最近还是在找工作,在面试某移动互联网公司之前认为自己对Java的GC机制已经相当了解,其他面试官问的时候也不存在问题,直到那天该公司一个做搜索的面试官问了我GC的问题,具体就是:老年代使用的是哪中垃圾 ...
- 【C#进阶系列】21 托管堆和垃圾回收
托管堆基础 一般创建一个对象就是通过调用IL指令newobj分配内存,然后初始化内存,也就是实例构造器时做这个事. 然后在使用完对象后,摧毁资源的状态以进行清理,然后由垃圾回收器来释放内存. 托管堆除 ...
- Java内存模型与垃圾回收
1.Java内存模型 Java虚拟机在执行程序时把它管理的内存分为若干数据区域,这些数据区域分布情况如下图所示: 程序计数器:一块较小内存区域,指向当前所执行的字节码.如果线程正在执行一个Java方法 ...
- ubifs核心对象 -- TNC和LPT
文件系统的核心问题是存储.这里面隐含2个问题:1)存储什么?2)存储到哪里?文件系统中的各种技术手段都是如何高效的解决这2个问题.ubifs用node标准化每一个存储对象,用lpr ...
- Java虚拟机之垃圾回收详解一
Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...
- JVM的内存区域划分以及垃圾回收机制详解
在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以 ...
随机推荐
- Android touch事件的派发流程
Android TouchEvent事件传递机制 通俗易懂,能够了解Touch事件派发的基本流程. Android中的dispatchTouchEvent().onInterceptTouchEven ...
- 攻城狮在路上(壹) Hibernate(十二)--- Hibernate的检索策略
本文依旧以Customer类和Order类进行说明.一.引言: Hibernate检索Customer对象时立即检索与之关联的Order对象,这种检索策略为立即检索策略.立即检索策略存在两大不足: A ...
- 2-01SQL的概述
SQL: Structured Query Languaage:结构化查询语言. 美国国家标准局ANSI. 国际标准化组织. T-SQL: Transact-SQL. T-SQL是SQL的扩展集. 对 ...
- WPF初学(一)——布局【良好界面的基础】
由Winform转到WPF的一部分人,很可能忽略掉布局,习惯性的使用固定定位.然而,没有良好的布局,后面界面控件画的再好看,花哨,都不过是鲜花插在牛粪上,很可能始终都是一坨??(呵呵). 闲话少说,首 ...
- 常见IE浏览器bug及其修复方案(双外边距、3像素偏移、绝对定位)
1. 双外边距浮动bug IE6和更低版本中存在双外边距浮动bug,顾名思义,这个Windows bug使任何浮动元素上的外边距加倍 bug重现: <!DOCTYPE html> < ...
- @property中strong跟weak的区别
strong关键字与retain关似,用了它,引用计数自动+1,用实例更能说明一切 @property (nonatomic, strong) NSString *string1; @property ...
- jackson对多态or多子类序列化的处理配置
[TOC] Jackson Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象. 多态类型的处理 jackson允许配置多态类型处理, ...
- 直接拿来用!最火的Android开源项目(一) (转)
对于开发者而言,了解当下比较流行的开源项目很是必要.利用这些项目,有时能够让你达到事半功倍的效果.为此,CSDN特整理了GitHub上最受欢迎的Android及iOS开源项目,本文详细介绍了20个An ...
- 智能车学习(十四)——K60单片机GPIO学习
一.头文件: #ifndef __MK60_GPIO_H__ #define __MK60_GPIO_H__ #include "MK60_gpio_cfg.h" /* * 定义管 ...
- Linux C编程(1) vim及gcc命令
1. 输入以下命令可以启动vi: (1) vi:不指定文件名,在保存文件时需要指定文件名. (2) vi 文件名:该文件既可以是已存在的,也可以是新建的. (3) vi ...