@@ -8,15 +8,27 @@ page_cache page_cache::__s_inst;
88span* page_cache::new_span (size_t k) {
99 assert (k > 0 && k < PAGES_NUM);
1010 // 先检查第k个桶是否有span
11+ // #ifdef PROJECT_DEBUG
12+ // LOG(DEBUG) << "before ***" << std::endl;
13+ // #endif
1114 if (!__span_lists[k].empty ())
12- return __span_lists->pop_front ();
15+ return __span_lists[k].pop_front (); // ? __span_lists->pop_front();
16+ // #ifdef PROJECT_DEBUG
17+ // LOG(DEBUG) << "after ***" << std::endl;
18+ // #endif
1319 // 第k个桶是空的->去检查后面的桶里面有无span,如果有,可以把它进行切分
1420 for (size_t i = k + 1 ; i < PAGES_NUM; i++) {
1521 if (!__span_lists[i].empty ()) {
16- // 可以开始切了
17- // 假设这个页是n页的,需要的是k页的
18- // 1. 从__span_lists中拿下来 2. 切开 3. 一个返回给cc 4. 另一个挂到 n-k 号桶里面去
22+ // 可以开始切了
23+ // 假设这个页是n页的,需要的是k页的
24+ // 1. 从__span_lists中拿下来 2. 切开 3. 一个返回给cc 4. 另一个挂到 n-k 号桶里面去
25+ #ifdef PROJECT_DEBUG
26+ LOG (DEBUG) << " before ***" << std::endl;
27+ #endif
1928 span* n_span = __span_lists[i].pop_front ();
29+ #ifdef PROJECT_DEBUG
30+ LOG (DEBUG) << " after ***" << std::endl;
31+ #endif
2032 span* k_span = new span;
2133 // 在n_span头部切除k页下来
2234 k_span->__page_id = n_span->__page_id ; // <1>
@@ -33,6 +45,9 @@ span* page_cache::new_span(size_t k) {
3345 */
3446 // 剩下的挂到相应位置
3547 __span_lists[n_span->__n ].push_front (n_span);
48+ // 存储n_span的首尾页号跟n_span的映射,方便pc回收内存时进行合并查找
49+ __id_span_map[n_span->__page_id ] = n_span;
50+ __id_span_map[n_span->__page_id + n_span->__n - 1 ] = n_span;
3651 // 这里记录映射(简历id和span的映射,方便cc回收小块内存时,查找对应的span)
3752 for (PAGE_ID j = 0 ; j < k_span->__n ; j++) {
3853 __id_span_map[k_span->__page_id + j] = k_span;
@@ -62,10 +77,50 @@ span* page_cache::map_obj_to_span(void* obj) {
6277 auto ret = __id_span_map.find (id);
6378 if (ret != __id_span_map.end ())
6479 return ret->second ;
65- LOG (FATAL);
80+ LOG (FATAL) << std::endl ;
6681 assert (false );
6782 return nullptr ;
6883}
6984
7085void page_cache::release_span_to_page (span* s) {
86+ // 对span前后对页尝试进行合并,缓解内存碎片问题
87+ while (true ) {
88+ PAGE_ID prev_id = s->__page_id - 1 ; // 前一块span的id一定是当前span的id-1
89+ // 拿到id如何找span: 之前写好的map能拿到吗?
90+ // 找到了,如果isuse是false,就能合并了(向前合并+向后合并)
91+ // 如果遇到了合并大小超过了128页了,也要停止了
92+ auto ret = __id_span_map.find (prev_id);
93+ if (ret == __id_span_map.end ()) // 前面的页号没有了,不合并了
94+ break ;
95+ span* prev_span = ret->second ;
96+ if (prev_span->__is_use == true ) // 前面相邻页的span在使用,不合并了
97+ break ;
98+ if (prev_span->__n + s->__n > PAGES_NUM - 1 ) // 合并出超过128页的span没办法管理,不合并了
99+ break ;
100+ s->__page_id = prev_span->__page_id ;
101+ s->__n += prev_span->__n ;
102+ __span_lists[prev_span->__n ].erase (prev_span); // 防止野指针,删掉
103+ delete prev_span; // 删掉这个span
104+ } // 向前合并的逻辑 while end;
105+ while (true ) {
106+ PAGE_ID next_id = s->__page_id + s->__n - 1 ; // 注意这里的页号是+n-1了
107+ auto ret = __id_span_map.find (next_id);
108+ if (ret == __id_span_map.end ()) // 后面的页号没有了
109+ break ;
110+ span* next_span = ret->second ;
111+ if (next_span->__is_use == true ) // 后面相邻页的span在使用,不合并了
112+ break ;
113+ if (next_span->__n + s->__n > PAGES_NUM - 1 ) // 合并出超过128页的span没办法管理,不合并了
114+ break ;
115+ s->__page_id ; // 起始页号不用变了,因为是向后合并
116+ s->__n += next_span->__n ;
117+ __span_lists[next_span->__n ].erase (next_span); // 防止野指针,删掉
118+ delete next_span;
119+ }
120+ // 已经合并完成了,把东西挂起来
121+ __span_lists[s->__n ].push_front (s);
122+ s->__is_use = false ;
123+ // 处理一下映射,方便别人找到我
124+ __id_span_map[s->__page_id ] = s;
125+ __id_span_map[s->__page_id + s->__n - 1 ] = s;
71126}
0 commit comments