遍历slub分配器申请的object(linux3.16)

这篇具有很好参考价值的文章主要介绍了遍历slub分配器申请的object(linux3.16)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我只是把active_obj的数量基本凑齐了,细节还没有去研究,可能有些地方是错的

之前遇到了一个设备跑了一段直接之后内存降低无法回收的问题。当时通过slabinfo看到某些slab池子里面active_objs和num_objs差距很大。slub分配器无法自己回收

(无法回收的原因有种这个说法,如果你申请了一个obj,实际上它会给去申请n个,然后拿一个给你。经过一段时间后n个都被申请完了。如果slub分配器想回收,只能是n个都被释放了才能回收,只要有其中一个未被释放,都不行。这个说法还没有去验证过。)

当时就想知道究竟是哪些人申请了内存没有释放 。所以就产生了去找active_objs的内存申请轨迹的想法

突然想到个问题。在设备启动时slabinfo如下:

# name            <active_objs> <num_objs> <objsize>

xxx                    6000               6000               yyyy

全部业务停掉,slabinfo如下

# name            <active_objs> <num_objs> <objsize>

xxx                    6000               10000               yyyy

active的数量都恢复了。只是总的数量增加了,无法回收。这种情况还会是因为部分人持有buffer,导致其他人无法被回收嘛?难道是这6000只是数量没有变化,申请者发生了变化??

我的环境里面使用的是slub分配器 。每一类object都会拥有一个cache(struct kmem_cache)。这个cache里面可以管理多个slab(代码里面其实是没有slab这个东西的,slab由2^order个连续的page组成,每个page里面又可以有多个object)

遍历slub分配器申请的object(linux3.16),linux

理论上我们只需要遍历所有slab里面所有的page,我们就可以找到所有的object(包含已分配和位未分配的)。

struct kmem_cache {
	struct kmem_cache_cpu __percpu *cpu_slab;
............................
	struct kmem_cache_node *node[MAX_NUMNODES];
};
struct kmem_cache_node {
	spinlock_t list_lock;
.......................
#ifdef CONFIG_SLUB
	unsigned long nr_partial;
	struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
	atomic_long_t nr_slabs;
	atomic_long_t total_objects;
	struct list_head full;
#endif
#endif

};

可以看到 kmem_cache里面有个node,这个node里面的partial是一个链表,里面挂的是部分空闲的page,链表full里面的page是全部都被分配出去的page(active obj主要在这个里面)。cpu_slab里面我不知道有没有用(感觉应该是有的,但是我本地试过都是空的,不用遍历也行),我遍历的时候还是去检查了它

最后代码如下

linux-3.16\mm\slub.c(需要开启slub debug)

account_active_obj里面的循环不需要,是我理解错了

print_tracking就可以打印内存申请释放信息

unsigned long account_active_obj(struct page *slab, struct kmem_cache *s, int order)
{
	void *start;
	void *last;
	void *p;
	struct page *page;
	unsigned long alloc_cnt = 0;
	int i = 0;
	/*
	最开始我以为slab是连续的几个page,
	链表里面只有起始的page,我们需要向后遍历2^order个page
	其实所有的page都在里面了
	*/
	//int num = 1 << order;
	int num = 1 << 0;
	if (NULL == slab)
	{
		//printk(KERN_EMERG "\r\n slab null\n");
		return 0;
	}
	unsigned long pfn = page_to_pfn(slab);

	start = page_address(slab);
	last = start;
	while (i < num)
	{
		page = pfn_to_page(pfn);
		//printk(KERN_EMERG "\r\n page->objects %d, page->inuse %d\n", page->objects, page->inuse);
		for_each_object(p, s, start, page->objects) {
			/*
			判断当前obj是否是空闲的,不是空闲的打印出申请者信息
			*/
			if (!on_freelist(s, page, last)) 
			{
				//print_tracking(s, last);
				alloc_cnt++;
			}
			last = p;
		}
		++i;
		++pfn;
	}
	return alloc_cnt;
}

unsigned long showinfo(struct kmem_cache *s)
{
	unsigned long alloc_cnt = 0;
	unsigned long flags;
	int cpu;
	struct page *page;

	int order = oo_order(s->oo);
	struct kmem_cache_node *n = s->node[0];
	spin_lock_irqsave(&n->list_lock, flags);
	
	list_for_each_entry(page, &n->partial, lru)
	{
		//printk(KERN_EMERG "\r\n n->partia\n");
		alloc_cnt +=account_active_obj(page, s, order);
	}
	list_for_each_entry(page, &n->full, lru)
	{
		//printk(KERN_EMERG "\r\n n->partial\n");
		alloc_cnt +=account_active_obj(page, s, order);
	}
	spin_unlock_irqrestore(&n->list_lock, flags);

	for_each_possible_cpu(cpu) {
			struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
			//printk(KERN_EMERG "\r\n cpu_slab\n");
			alloc_cnt +=account_active_obj(c->page, s, order);
			alloc_cnt +=account_active_obj(c->partial, s, order);;
	}
	//printk(KERN_EMERG "\r cache %s used cnt %lu, order %d\n", s->name, alloc_cnt, order);
	return alloc_cnt;
}

下面这个代码是修改显示的地方 

int cache_show(struct kmem_cache *s, struct seq_file *m)
{
......................................
	alloc_cnt = showinfo(s);
	seq_printf(m, "%-17s %6lu(%lu) %6lu %6u %4u %4d",
		   cache_name(s), sinfo.active_objs, alloc_cnt, sinfo.num_objs, s->size,
		   sinfo.objects_per_slab, (1 << sinfo.cache_order));

.......................
	
	return 0;
}

实际效果展示:

cat /proc/slabinfo

基本数量能对的上

遍历slub分配器申请的object(linux3.16),linux文章来源地址https://www.toymoban.com/news/detail-807800.html

到了这里,关于遍历slub分配器申请的object(linux3.16)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 架构师成长之路Redis第一篇|Redis 安装介绍以及内存分配器jemalloc

    Redis官网:https://redis.io/download/ 下载安装二进制文件 可下载安装最新版Redis7.2.0,或者可选版本6.x 我这里下载6.2.13和7.2最新版本,后面我们都是安装6.2.13版本的信息进行讲解 二进制文件安装步骤 安装前期准备: 安装gcc yum install gcc 压缩文件 tar -xzf redis6.2.13.tar.gz 编译 cd redis-x

    2024年02月11日
    浏览(51)
  • Flink--7、窗口(窗口的概念、分类、API、分配器、窗口函数)、触发器、移除器

                           星光下的赶路人star的个人主页                        内心的平静始于不再让他人掌控你的感情 在批处理统计中,我们可以等待一批数据都到齐后,统一处理。但是在实时处理统计中,我们是来一

    2024年02月08日
    浏览(47)
  • [linux kernel]slub内存管理分析(5) kfree

    省流 如果对代码细节不感兴趣,可以直接跳转底部内存释放逻辑总结。 前情回顾 关于slab几个结构体的关系和初始化和内存分配的逻辑请见: [linux kernel]slub内存管理分析(0) 导读 [linux kernel]slub内存管理分析(1) 结构体 [linux kernel]slub内存管理分析(2) 初始化 [linux kernel]slub内存管

    2023年04月09日
    浏览(61)
  • [linux kernel]slub内存管理分析(4) 细节操作以及安全加固

    前情回顾 关于slab几个结构体的关系和初始化和内存分配的逻辑请见: [linux kernel]slub内存管理分析(0) 导读 [linux kernel]slub内存管理分析(1) 结构体 [linux kernel]slub内存管理分析(2) 初始化 [linux kernel]slub内存管理分析(2.5) slab重用 [linux kernel]slub内存管理分析(3) kmalloc 描述方法约定

    2023年04月09日
    浏览(55)
  • nlohmann json:通过items遍历object/array

    编译运行输出: key: one, value: 1 key: two, value: 2 key: 0, value: 1 key: 1, value: 2 key: 2, value: 4 key: 3, value: 8 key: 4, value: 16  可以看到对于object可以通过key()和value()拿到键值对 对

    2024年02月13日
    浏览(46)
  • 【Android】使用对象池(Object Pool)来缓存已经创建的字节数组,避免频繁地进行内存分配和回收操作提高性能

    在Android中,使用new byte[]创建字节数组是在堆上分配内存,不会直接导致Native内存的增长。但是,如果我们频繁地创建和销毁字节数组,就可能会导致堆内存不足,并触发GC,从而影响应用程序的性能。 在Android中,堆内存的大小是有限制的。如果我们频繁地创建和销毁字节数

    2024年02月09日
    浏览(51)
  • 前端js 数据结构:对象 object、数组Array 、Map 的创建、增删改 / 遍历数据

    对象:由一组键值对组成的无序集合,可以通过键来获取对应的值。 每个键值对中的键是唯一的,值可以是任意类型的数据。 对象通常用来表示实体的属性和方法。 1.1.1 对象字面量(最常用): {} 对象字面量:通过在大括号 {} 中定义对象的属性和方法来创建对象。 这是最简单

    2024年01月21日
    浏览(54)
  • 使用java8 新特性stream流对List<Map<String, Object>>集合进行遍历、过滤、查询、去重、排序、分组

    对于一个ListMapString, Object类型的数据,可以使用Java 8的新特性stream流来进行遍历、过滤、查询、去重、排序、分组等操作。 遍历: 过滤: 查询: 去重: 排序: 分组:

    2024年02月10日
    浏览(69)
  • Linux中DNS的分离解析和自动分配

     1.DNS分离解析实验 1.1 实验目的  1.2 实验准备 1.3 实验设计 1.4 实验操作具体步骤   第一步:对默认网卡进行设置(Linux DNS解析服务器) 第二步:新添加一张网卡,进行网关设置 (Linux DNS解析服务器)  第三步:安装bind服务(此步省略,上一篇博客有详细过程) 第四步:

    2024年02月05日
    浏览(31)
  • Linux动态分配IP与正向解析DNS

    目录 一、DHCP分配 1. 动态分配 1.1 服务端服务安装 1.2 修改服务端dhcp配置  1.3 修改客户端dhcp,重启查询网卡信息 2. 根据mac固定分配 2.1 修改服务器端dhcp服务配置 2.2 客户端自动获取,查看网卡信息 二、时间同步 1. 手动同步 2. 自动同步 3. 搭建本地时间同步服务器 3.1 图示 3

    2024年02月01日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包