kmalloc最大能申请多少内存?

您所在的位置:网站首页 hmcl物理内存最大多少 kmalloc最大能申请多少内存?

kmalloc最大能申请多少内存?

2024-04-02 08:31| 来源: 网络整理| 查看: 265

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) if (size > KMALLOC_MAX_CACHE_SIZE) return kmalloc_large(size, flags); #ifndef CONFIG_SLOB if (!(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.c static __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 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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3