1. 概述

本文主要分析kmalloc接口申请内存的大小情况,用于记录kmalloc分配内存的过程。

内核版本:Linux 4.9

2.分析记录

针对kmalloc最大能申请多少内存,网上众说纷纭,意见各不相同,因此最终决定自己针对源码分析,记录如下:

首先看kmalloc()函数实现,在include/linux/slab.h中,代码如下:

#ifdef CONFIG_SLAB
/** The largest kmalloc size supported by the SLAB allocators is* 32 megabyte (2^25) or the maximum allocatable page order if that is* less than 32 MB.** WARNING: Its not easy to increase this value since the allocators have* to do various tricks to work around compiler limitations in order to* ensure proper constant folding.*/
#define KMALLOC_SHIFT_HIGH  ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \(MAX_ORDER + PAGE_SHIFT - 1) : 25)
#define KMALLOC_SHIFT_MAX   KMALLOC_SHIFT_HIGH
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW   5
#endif
#endif#ifdef CONFIG_SLUB
/** SLUB directly allocates requests fitting in to an order-1 page* (PAGE_SIZE*2).  Larger requests are passed to the page allocator.*/
#define KMALLOC_SHIFT_HIGH  (PAGE_SHIFT + 1)
#define KMALLOC_SHIFT_MAX   (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW   3
#endif
#endif#ifdef CONFIG_SLOB
/** SLOB passes all requests larger than one page to the page allocator.* No kmalloc array is necessary since objects of different sizes can* be allocated from the same page.*/
#define KMALLOC_SHIFT_HIGH  PAGE_SHIFT
#define KMALLOC_SHIFT_MAX   (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW   3
#endif
#endif/* Maximum allocatable size */
#define KMALLOC_MAX_SIZE    (1UL << KMALLOC_SHIFT_MAX)
/* Maximum size for which we actually use a slab cache */
#define KMALLOC_MAX_CACHE_SIZE  (1UL << KMALLOC_SHIFT_HIGH)
/* Maximum order allocatable via the slab allocagtor */
#define KMALLOC_MAX_ORDER   (KMALLOC_SHIFT_MAX - PAGE_SHIFT)static __always_inline void *kmalloc(size_t size, gfp_t flags)
{if (__builtin_constant_p(size)) {if (size > KMALLOC_MAX_CACHE_SIZE)return kmalloc_large(size, flags);
#ifndef CONFIG_SLOBif (!(flags & GFP_DMA)) {int index = kmalloc_index(size);if (!index)return ZERO_SIZE_PTR;return kmem_cache_alloc_trace(kmalloc_caches[index],flags, size);}
#endif}return __kmalloc(size, flags);
}

其中__builtin_constant_p()是编译器内函数,用于判断传入的参数是否为常量,因此动态分配内存一般不会进入该if分支,重点分析__kmalloc()实现即可。

__kmalloc()实现分三种情况,一种是slab,一种是slub,最后一种是slob,其实现分别如下:

2.1 slab的kmalloc()


static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,unsigned long caller)
{struct kmem_cache *cachep;void *ret;if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))return NULL;cachep = kmalloc_slab(size, flags);if (unlikely(ZERO_OR_NULL_PTR(cachep)))return cachep;ret = slab_alloc(cachep, flags, caller);kasan_kmalloc(cachep, ret, size, flags);trace_kmalloc(caller, ret,size, cachep->size, flags);return ret;
}void *__kmalloc(size_t size, gfp_t flags)
{return __do_kmalloc(size, flags, _RET_IP_);
}
EXPORT_SYMBOL(__kmalloc);

当Linux系统配置的内存管理器为slab时,如果分配的内存大于KMALLOC_MAX_CACHE_SIZE,就直接返回NULL,因此支持slab分配器的系统,kmalloc()分配的内存不能超过KMALLOC_MAX_CACHE_SIZE,该宏的计算见include/linux/slab.h。

当MAX_ORDER=11,PAGE_SHIFT=12(4kB)时,KMALLOC_MAX_CACHE_SIZE算出来是4MB,说明支持slab的系统,通过kmalloc()最大申请的内存不能超过4M。

但该值是跟随CONFIG_FORCE_MAX_ZONEORDER配置项和PAGE_SHIFT这两个宏决定。因此具体还需要看系统中这两个宏的值。

2.2 slub的kmalloc()

//mm/slub.c
void *__kmalloc(size_t size, gfp_t flags)
{struct kmem_cache *s;void *ret;if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))return kmalloc_large(size, flags);s = kmalloc_slab(size, flags);if (unlikely(ZERO_OR_NULL_PTR(s)))return s;ret = slab_alloc(s, flags, _RET_IP_);trace_kmalloc(_RET_IP_, ret, size, s->size, flags);kasan_kmalloc(s, ret, size, flags);return ret;
}
EXPORT_SYMBOL(__kmalloc);
//mm/slab_common.c
void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{void *ret;struct page *page;flags |= __GFP_COMP;page = alloc_pages(flags, order);ret = page ? page_address(page) : NULL;kmemleak_alloc(ret, size, 1, flags);kasan_kmalloc_large(ret, size, flags);return ret;
}
EXPORT_SYMBOL(kmalloc_order);

当Linux系统配置的内存管理器为slub时,如果分配的内存大于KMALLOC_MAX_CACHE_SIZE,就通过kmalloc_large()接口分配内存,最终会调用到kmalloc_order()函数,该函数直接从buddy子系统分配pages。因此只要系统上内存足够,就可以分配出足够大的内存,只是该内存不是属于slub管理器管理的对象而已。

系统支持slub内存管理器,KMALLOC_MAX_CACHE_SIZE宏的值只和PAGE_SHIFT有关,当PAGE_SHIFT=12时,KMALLOC_MAX_CACHE_SIZE算出来是8kB

2.3 slob的kmalloc()

//mm/slob.cstatic __always_inline void *
__do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
{unsigned int *m;int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);void *ret;gfp &= gfp_allowed_mask;lockdep_trace_alloc(gfp);if (size < PAGE_SIZE - align) {if (!size)return ZERO_SIZE_PTR;m = slob_alloc(size + align, gfp, align, node);if (!m)return NULL;*m = size;ret = (void *)m + align;trace_kmalloc_node(caller, ret,size, size + align, gfp, node);} else {unsigned int order = get_order(size);if (likely(order))gfp |= __GFP_COMP;ret = slob_new_pages(gfp, order, node);trace_kmalloc_node(caller, ret,size, PAGE_SIZE << order, gfp, node);}kmemleak_alloc(ret, size, 1, gfp);return ret;
}void *__kmalloc(size_t size, gfp_t gfp)
{return __do_kmalloc_node(size, gfp, NUMA_NO_NODE, _RET_IP_);
}
EXPORT_SYMBOL(__kmalloc);

当Linux系统配置的内存管理器为slob时,如果分配的内存大于PAGE_SIZE,就会从buddy子系统分配pages。因此只要系统上内存足够,就可以分配出足够大的内存。

3.结论

综上所述,kmalloc()能分配多大内存,是依赖系统的配置决定。

kmalloc最大能申请多少内存?相关推荐

  1. 通过伙伴系统申请内核内存的函数有哪些?

    本文转自:http://blog.chinaunix.net/space.php?uid=22566367&do=blog&id=2747207 在物理页面管理上实现了基于区的伙伴系统 ...

  2. linux申请大块内存,linux 内存看一篇就够了(多图)

    image 正文 0 内存模块 image 1 linux内存总体布局:内存分成用户态和内核态 4G进程地址空间解析 image image 内核地址空间 image image 进程地址空间 ima ...

  3. linux 用户进程结束后 malloc申请的内存会自动释放吗,进程退出后malloc的内存是否会被释放?

    当一个进程退出后,不管是正常退出或者是异常退出,操作系统都会释放这个进程的资源.包括这个进程分配的内存,打开的文件等等. 内存泄露的前提是进程一直在运行:进程一旦退出,所占的整个虚拟内存都被销毁,所有 ...

  4. 【三分钟学习FFMPEG一个知识点】FFMPEG关于avio_alloc_context申请使用内存释放问题

    问题: 使用ffmpeg发现av_malloc申请的内存最后不能用av_free函数释放,会崩溃. 代码示例: unsigned char * iobuffer = NULL; iobuffer = ...

  5. Yarn申请的内存的精确计算(转载+应用到自己的情况中)

    这篇博客主要是利用[1]中的流程来尝试估算自己在运行spark on yarn模式时申请的内存数值. 一个spark任务会产生几个Container? count = ExecutorNum + 1 ...

  6. 关于用函数指针参数申请动态内存的问题

    今天在写一个Binary Search Tree的程序时,发现其插入有问题,下面是插入程序,每次插入完成后,节点还是NULL. template<typename Object> void ...

  7. c语言链表错误,C语言创建链表错误之通过指针参数申请动态内存实例分析

    本文实例讲述了C语言创建链表中经典错误的通过指针参数申请动态内存,分享给大家供大家参考之用.具体实例如下: #include #include // 用malloc要包含这个头文件 typedef s ...

  8. C语言为四维数组申请动态内存空间的方法(二)

    尝试了用堆栈的方式为四维数组申请动态内存空间,并将申请内存的操作封装成了子函数,方便在主程序中使用.希望对大家有用.代码如下: #include <stdio.h> #include &l ...

  9. C语言为四维数组申请动态内存空间的方法(一)

    尝试了用结构体为四维数组申请动态内存空间,希望对大家有用.代码如下: #include <stdio.h> #include <stdlib.h>typedef struct ...

最新文章

  1. 2022-2028年中国润滑油基础油行业市场研究及前瞻分析报告
  2. Microbiome:南土所褚海燕组揭示长期施肥抑制根际微生物固氮的作用机制
  3. Tomcat单向Https验证搭建,亲自实现与主流浏览器、Android/iOS移动客户端安全通信
  4. 复制表数据和结构的方法
  5. Mysql数据库设计及常见问题
  6. web服务器获取项目路径问题,读取web项目properties文件路径 解决tomcat服务器找不到properties路径问题...
  7. Missed in my life《2013》
  8. java清屏_【图片】请问java编写中如何做到清屏啊。。。_java吧_百度贴吧
  9. 2. 性能测试中常见术语集合
  10. 金融市场中的NLP——情感分析
  11. 2021年软考网络工程师备考资料
  12. 《HTTP权威指南》– 6.代理
  13. HoG特征以及SVM的配合
  14. 群辉 DSM 7.0 Docker 启动 AdguardHome 屏蔽广告
  15. c语言此项目已过期是什么意思,Visual Studio 2017 许可证已过期解决方案
  16. C语言程序课程设计—读心术
  17. 5分绩点转4分_4分绩点与百分制转换方法
  18. rtsp有没有好使_求几个可用的稍微清晰点的RTSP播放源,最好是上海的!
  19. 初学爬虫-笔趣阁爬虫
  20. 新功能上线 | “性能怪兽”Amazon Graviton2 正式登陆亚马逊云科技中国区域!

热门文章

  1. mac idea实现全局替换
  2. 0 pandas概述--1文件读取与写入--2 基本操作
  3. 分析报告撰写毫无头绪?掌握这个小技巧即可迎刃而解
  4. 计算机组装与系统安装,电脑组装后如何安装系统图文教程
  5. UWB中TOF测距法的公式推导
  6. dataframe的head方法_pandas——Datafram的基本操作方法
  7. 程序员刚毕业,先去大厂镀金还是先去小厂攒经验?
  8. 蓝桥杯——ALGO998——娜神平衡
  9. 你会休息吗?掌握最高效的休息方式
  10. 时间序列R语言操作2——白噪声和随机游走模型