免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4400 | 回复: 6
打印 上一主题 下一主题

关于linux Slub的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-09-24 22:49 |只看该作者 |倒序浏览
看到一本关于内核的书上面讲到内存管理那一章的时候有一点疑惑,不知道是不是书上没讲明白,还是我没理解透。
就是在slub分配与回收的时候,前面说每一个kmem_cache结构一次会批发2^order个物理页面,称为一个PageFrame,并将这个PageFrame处理成object链表,让kmem_cache_cpu的page指针指向第一个page页面,page结构中的inuse初始化为该PageFrame中总的object数量........分配策略倒是没什么问题能看懂。但是释放的时候说由释放的object首地址计算出所属的page结构,这个也能理解。但是因为一个PageFrame可能包含多个page结构,所以由这个object算出来的地址不一定是第一个page结构,比如第二个或者以后的,那么它后面说将page结构中的inuse没释放一个object减1,到减为0那么说明这个PageFrame已经全部释放,那么就可以释放这个PageFrame了,刚才说了只是将第一个page结构的inuse初始化为PageFrame的总个数(这个是自己的想法不知道是不是)那么要是算出来不是第一个page结构那么该上哪儿减呢?它也不知道到底谁是第一个page结构啊 所以这个地方有点疑惑

总结一下问题:怎根据一个object地址找到该PageFrame的第一个page结构,还有释放PageFrame的时候怎么知道这个PageFrame一共有一个page?

论坛徽章:
0
2 [报告]
发表于 2011-09-25 10:22 |只看该作者
你的问题是从buddy分配页的问题,不是slub本身的问题

  1. __alloc_pages --> __alloc_pages_internal --> get_page_from_freelist --> buffered_rmqueue  --> prep_new_page --> prep_compound_page --> set_compound_order
复制代码

  1. free_pages --> __free_one_page --> destroy_compound_page -->

  2.         if (unlikely(compound_order(page) != order))
  3.                 bad_page(page);
复制代码
也就是释放和分配都会把order标记到第一个page的结构上,你在slub中操作的也是拿这个page来操作的,一直拿着这个,所以就不存在你说的释放到中间的page结构去

分配释放都是要传order的,order会在释放时检查,所以不存在只释放一个page的情况

问题根源就在于:你根本不会和中间的page结构联系上

论坛徽章:
0
3 [报告]
发表于 2011-09-26 12:10 |只看该作者
本帖最后由 s200661524 于 2011-09-26 12:32 编辑

回复 2# unbutun
谢谢你的回复,不过您可能是没有理解我的问题,或者我没说清楚。页的释放过程根据伙伴关系能理解,不明白的就是在slub小内存管理上,我现在的问题出在小内存管理上,比如申请了一个task_struct结构的释放。
  1. void kfree(const void *x)
  2. {
  3.         struct page *page;
  4.         void *object = (void *)x;

  5.         if (unlikely(ZERO_OR_NULL_PTR(x)))
  6.                 return;

  7.         page = virt_to_head_page(x);
  8.         if (unlikely(!PageSlab(page))) {
  9.                 BUG_ON(!PageCompound(page));
  10.                 put_page(page);
  11.                 return;
  12.         }
  13.         slab_free(page->slab, page, object, __builtin_return_address(0));
  14. }
复制代码
上面根据一个释放的地址x找到对应的page结构。
我看的书《内核源代码导读》,上面说SLUB不记录每个pageframe的信息,这些信息是释放过程是根据object计算出PFN,也就是页编号,根据这个页编号(下标)可以找到对应的page结构。那么怎么根据object计算出属于该order下的第一个gapg结构呢?
修改:找到了,就是顺着page = virt_to_head_page(x);这条线找的
  1. static inline struct page *virt_to_head_page(const void *x)
  2. {
  3.         struct page *page = virt_to_page(x);
  4.         return compound_head(page);
  5. }
复制代码
page = virt_to_page(x)这个好理解,都是线性映射,相差一个固定的地址,所以上面说得object计算出PFN,PFN可以找到对应的page结构。
  1. static inline struct page *compound_head(struct page *page)
  2. {
  3.         if (unlikely(PageTail(page)))
  4.                 return page->first_page;
  5.         return page;
  6. }
复制代码
初始化的时候应该是将每个页面都指向了第一个页面,等会去找源码看看

论坛徽章:
0
4 [报告]
发表于 2011-09-26 22:21 |只看该作者
回复 3# s200661524


    从你的回复,我还是理解成了,就是一个object找到其所在的page,然后将其所在的page释放掉了,而不是释放掉连续的一个页组


如果我们理解的一致的话:
                      我想还是和buddy联系较大,是slub从buddy分配内存后释放的问题,而根源在于一块小的内存如何归还到一整个页组的问题,就是




那么就是上面的compound来找的,buddy是不会让这种事发生的,其实问题和申请了3个连续的页,释放中间的那个是一样的问题


不知道我们理解有没有出入

论坛徽章:
0
5 [报告]
发表于 2011-09-27 10:23 |只看该作者
本帖最后由 s200661524 于 2011-09-27 10:42 编辑

回复 4# unbutun

呵呵,谢谢你,图片上就是我的问题,某次释放的obj属于2^order个page页面中间的某一个page,现在释放这个obj,所以要找到它所对应的页面,准确的说是这2^order个page的第一个页面,因为需要修改该页面中的inuse参数,每释放一个obj,就要将其减1,而在这个数减到0之前该frampage是不会归还给buddy的,假如是第一次释放该framepage中的obj,显然不会有对buddy的操作,所以我问的问题应该还是跟buddy没有关系的,而且就算是该framepage中所有的obj释放玩了也不一定会归还到buddy吧,可能会挂在kmem_cache的kmem_cache_node的partial链表中缓存起来,以共下次分配,而且搜索算法中也提到过先看kmem_cache_cpu的freelist是否为空,如果不为空就在这个结构上分配,如果是就会去kmem_cache_node的partial链表上去找。再没有才会去buddy分配2^order个page物理页面。

     另外你说的是对的,内存管理模块不会允许释放某一次申请的2^order个页面中单独的一个页面,但是我的问题也没有涉及到释放一个page(4K)大小的页面,只是释放一个obj(比如32byte)到它所属的framepage里面去并挂接到对应page结构的freelist链表上这个过程中有点疑惑。
     在这里又有点疑惑了,假如有一次申请到了4个页面,编号为0,1,2,3,4。0号页面是这个framepage的第一个页面,采用0号页面的page结构来管理这次分配的4个页面。假如根据某次释放的obj地址算出该obj属于编号2的页面,那么这个obj是挂接到编号2的page结构的freelist上,还是通过编号2的page结构的firstpage成员找到编号0页面的page结构,然后挂接到0号page结构的freelist上呢?按照我的理解应该是挂接到0号page结构的freelist链表上,因为inuse成员(也就是该framepage总的obj个数,可以指示该framepage的所有obj是否释放完)只会在0号page结构中初始化,所以必须挂接到0号page上然后对inuse减1,不知道我的理解是不是对的。

谢谢你的回复!

论坛徽章:
16
2015亚冠之吉达阿赫利
日期:2015-08-17 11:21:462015年迎新春徽章
日期:2015-03-04 09:58:11酉鸡
日期:2014-12-07 09:06:19水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47
6 [报告]
发表于 2011-09-28 16:11 |只看该作者
本帖最后由 embeddedlwp 于 2011-09-28 16:13 编辑

回复 5# s200661524


    你的理解应该是正确的,因为一个slab只用第一个页的相关字段,如freelist,slab,inuse等来管理整个slab。2号页的那些字段此时不被使用的。
  1. union {  
  2.            atomic_t _mapcount;        /* Count of ptes mapped in mms,
  3.                                     * to show when page is mapped
  4.                                     * & limit reverse map searches.
  5.                                     */  
  6.            struct {                /* SLUB */  
  7.                    u16 inuse;  
  8.                    u16 objects;  
  9.            };  
  10.    };  
  11.   
  12.    union {  
  13.        struct {  
  14.            unsigned long private;  
  15.            struct address_space *mapping;  
  16.        };  
  17.        struct kmem_cache *slab;        /* SLUB: Pointer to slab */  
  18.        struct page *first_page;        /* Compound tail pages */  
  19.    };  
  20.   
  21.    union {  
  22.            pgoff_t index;                /* Our offset within mapping. */  
  23.            void *freelist;                /* SLUB: freelist req. slab lock */  
  24.    };  
复制代码
他们都是union的,所以并不增加struct page结构的大小,也只有是slab第一个物理页框的页描述符的时候这些字段才有效。

论坛徽章:
0
7 [报告]
发表于 2011-09-29 09:19 |只看该作者
回复 6# embeddedlwp
谢谢回复!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP