Linux平台上几个常见内核内存分配函数
- 格式:doc
- 大小:25.50 KB
- 文档页数:3
linux 申请大容量内存的方法【原创版4篇】目录(篇1)1.引言:介绍 Linux 系统中申请大容量内存的需求2.内核空间申请内存的方法:讲解 kmalloc 函数及其特点3.用户态申请内核态内存的方法:介绍 brk 系统调用、setfs、getfs 以及 dommap 等方法4.Linux 内存管理机制:概述地址空间、页(page)管理以及物理内存分配5.预留内存和大块内存申请:讨论内核对于大内存申请的优化方法6.结论:总结 Linux 申请大容量内存的方法及特点正文(篇1)在 Linux 系统中,有时我们需要申请大容量的内存空间以满足程序运行的需求。
本文将介绍几种在 Linux 系统中申请大容量内存的方法。
首先,我们可以使用 kmalloc 函数来申请内核空间内存。
kmalloc 函数的原型为:void *kmalloc(size_t size, int flags),其中 size 表示要分配的内存块大小,flags 表示分配标志,常用的有 (会引起睡眠) 和 (不引起睡眠,分配不到,立即返回)。
使用 kmalloc 函数申请的内存位于内核物理内存映射区域,物理上连续,与真实的物理地址只有一个固定偏移。
其次,如果我们需要在内核态使用用户态地址空间,可以采用以下几种方法:使用 brk 系统调用、setfs、getfs 以及 dommap 等。
这些方法可以在内核态和用户态之间映射物理内存,从而实现内核态访问用户态地址空间。
Linux 内存管理机制中,地址空间分为三个区域:DMA、normal 和highmem。
物理内存分配时,内核会根据不同的内存需求选择合适的区域进行分配。
而页(page)是 Linux 内存管理的基本单位,通常一页为 4KB。
在初始化时,内核为每个物理内存页建立一个 page 的管理结构。
针对大内存申请,Linux 内核也提供了一些优化方法。
例如,在申请大容量内存时,内核可以采用伙伴系统进行分配。
linux原子操作函数Linux原子操作函数是一组用于实现多线程同步和互斥的函数。
在并发编程中,多个线程同时访问共享资源时,可能会导致数据的不一致或竞争条件的发生。
原子操作函数可以保证多线程之间的顺序性和一致性,从而避免了竞争条件的产生。
原子操作函数的特点是不可分割和不可中断,即在执行原子操作期间,不会被其他线程打断或者分割成多个步骤执行。
这种特性保证了原子操作的完整性,使多线程之间可以安全地共享资源。
Linux提供了多个原子操作函数,其中最常用的有以下几个:1. atomic_inc(原子增加):该函数用于对指定的整型变量进行原子递增操作。
它保证了递增操作的完整性,不会被其他线程打断或者分割成多个步骤执行。
该函数常用于实现计数器等功能。
2. atomic_dec(原子减少):与atomic_inc函数类似,该函数用于对指定的整型变量进行原子递减操作。
同样地,它也保证了递减操作的完整性。
3. atomic_add(原子加法):该函数用于对指定的整型变量进行原子加法操作。
它可以将一个给定的值原子地加到指定的变量上,保证了整个加法操作的完整性和一致性。
4. atomic_sub(原子减法):与atomic_add函数类似,该函数用于对指定的整型变量进行原子减法操作。
它可以将一个给定的值原子地从指定的变量上减去。
5. atomic_xchg(原子交换):该函数用于原子地交换两个指定的值。
它可以保证交换操作的完整性,不会被其他线程打断。
6. atomic_cmpxchg(原子比较并交换):该函数用于比较指定的变量的值与给定的期望值是否相等,如果相等则用新的值替换旧的值。
它是一种常用的原子操作,可以用于实现互斥锁等功能。
除了上述常用的原子操作函数外,Linux还提供了其他一些原子操作函数,如atomic_and、atomic_or、atomic_xor等,它们分别用于进行按位与、按位或和按位异或的原子操作。
glib常⽤库函数和⼀些定义glib库是Linux平台下最常⽤的C语⾔函数库,它具有很好的可移植性和实⽤性。
glib是Gtk +库和Gnome的基础。
glib可以在多个平台下使⽤,⽐如Linux、Unix、Windows等。
glib为许多标准的、常⽤的C语⾔结构提供了相应的替代物。
使⽤glib库的程序都应该包含glib的头⽂件glib.h。
########################### glib基本类型定义: ##############################整数类型:gint8、guint8、gint16、guint16、gint32、guint32、gint64、guint64。
不是所有的平台都提供64位整型,如果⼀个平台有这些, glib会定义G_HAVE_GINT64。
类型gshort、glong、gint和short、long、int完全等价。
布尔类型:gboolean:它可使代码更易读,因为普通C没有布尔类型。
Gboolean可以取两个值:TRUE和FALSE。
实际上FALSE定义为0,⽽TRUE定义为⾮零值。
字符型:gchar和char完全⼀样,只是为了保持⼀致的命名。
浮点类型:gfloat、gdouble和float、double完全等价。
指针类型:gpointer对应于标准C的void *,但是⽐void *更⽅便。
指针gconstpointer对应于标准C的const void *(注意,将const void *定义为const gpointer是⾏不通的########################### glib的宏 ##############################⼀些常⽤的宏列表#include <glib.h>TRUEFALSENULLMAX(a, b)MIN(a, b)ABS ( x )CLAMP(x, low, high)TRUE / FALSE / NULL就是1 / 0 / ( ( v o i d * ) 0 )。
linux系统内核参数优化-linux快速⼊门教程内核的 shmall 和 shmmax 参数SHMMAX= 配置了最⼤的内存segment的⼤⼩ ------>这个设置的⽐SGA_MAX_SIZE⼤⽐较好。
SHMMIN= 最⼩的内存segment的⼤⼩SHMMNI= 整个系统的内存segment的总个数SHMSEG= 每个进程可以使⽤的内存segment的最⼤个数配置信号灯( semphore )的参数:SEMMSL= 每个semphore set⾥⾯的semphore数量 -----> 这个设置⼤于你的process的个数吧,否则你不得不分多个semphore set,好像有process+n之说,我忘了n是⼏了。
SEMMNI= 整个系统的semphore set总数SEMMNS=整个系统的semphore总数shmall 是全部允许使⽤的共享内存⼤⼩,shmmax 是单个段允许使⽤的⼤⼩。
这两个可以设置为内存的 90%。
例如 16G 内存,16*1024*1024*1024*90% = 15461882265,shmall 的⼤⼩为 15461882265/4k(getconf PAGESIZE可得到) = 3774873。
修改 /etc/sysctl.confkernel.shmmax=15461882265kernel.shmall=3774873kernel.msgmax=65535kernel.msgmnb=65535执⾏ sudo sysctl -p可以使⽤ ipcs -l 看结果。
ipcs -u 可以看到实际使⽤的情况========================================================================linux 内存管理⼀、前⾔本⽂档针对OOP8⽣产环境,具体优化策略需要根据实际情况进⾏调整;本⽂档将在以下⼏个⽅⾯来阐述如何针对RedHat Enterprise Linux 进⾏性能优化。
linux内存分配机制Linux操作系统的内存管理机制是指操作系统如何管理和分配系统的物理内存。
Linux使用虚拟内存管理机制来管理内存资源,以提供给应用程序更大的内存空间并保证系统的稳定性。
Linux的内存管理机制包括以下几个方面:1.虚拟内存管理:虚拟内存是一种将主存中的物理地址与应用程序中的虚拟地址进行映射的技术。
通过虚拟内存管理机制,Linux可以将应用程序需要的内存空间按需从硬盘加载到物理内存,以满足应用程序的要求。
这样,应用程序能够访问比物理内存更大的内存空间,并且不需要关心实际的物理内存地址。
2.页面调度和换入换出:Linux将内存按照固定大小的页面(通常为4KB)进行管理。
物理内存被分成多个页面框,每个页面框可以存放一个页面。
当应用程序需要更多内存时,Linux会将一部分不常用的页面从物理内存中换出到硬盘上的交换空间,以腾出空间给新的页面。
而当应用程序访问换出到硬盘的页面时,Linux会将其换入到物理内存中。
3.页表和地址映射:为了实现虚拟内存的管理,Linux使用页表来存储虚拟地址与物理地址之间的映射关系。
每个进程都有自己的页表,用于将进程的虚拟地址转换为物理地址。
Linux使用多级页表来管理大内存空间,以节省内存空间的开销。
4.内存分配算法:Linux通过伙伴系统进行内存的分配。
伙伴系统将整个物理内存按照2的幂次进行划分,并以块为单位进行分配。
当应用程序请求一定大小的内存时,Linux会查找并分配与请求大小最接近的2的幂次块。
如果没有找到合适的块,则会从较大的块中进行分割,直到找到合适的块。
5.内存回收和回收算法:Linux通过页面置换算法回收不再使用的内存页面,以便将其分配给其他进程。
常用的页面置换算法包括最近最少使用(LRU)算法和时钟置换算法。
Linux还通过SLAB分配器来回收和管理内核对象的内存。
总结起来,Linux的内存分配机制包括虚拟内存管理、页面调度和换入换出、页表和地址映射、内存分配算法以及内存回收和回收算法。
linux内核进程cpu调度基本原理Linux内核的CPU调度基本原理是通过多任务处理,将CPU 时间片分配给不同的进程或线程来实现。
1. 调度策略:Linux内核支持多种调度策略,包括先来先服务(FCFS)、时间片轮转、优先级调度等。
默认的调度策略是时间片轮转调度策略,即每个进程被分配一个时间片,在时间片用完之后,将CPU切换到下一个就绪状态的进程上。
2. 就绪队列:内核会维护一个就绪队列,存放所有准备好运行但还未分配CPU时间的进程。
根据进程的优先级和调度策略,内核会从就绪队列中选择一个合适的进程来执行。
3. 进程优先级:每个进程都有一个优先级值,表示其重要性和紧急程度。
较高优先级的进程在调度时会获得更多的CPU时间。
Linux内核使用动态优先级调度策略,根据进程的历史行为和资源使用情况动态调整进程的优先级。
4. 时间片和抢占:时间片是CPU分配给进程的最小单位,当一个进程的时间片用完后,如果它还未完成,内核会将其置于就绪队列末尾,并将CPU分配给下一个就绪进程。
此外,Linux 内核支持抢占式调度,即当一个优先级更高的进程出现时,可立
即抢占当前运行的进程,将CPU资源分配给新的进程。
5. 实时进程:除了普通进程,Linux内核还支持实时进程。
实时进程具有更高的优先级和较小的延迟要求,它们得到更快的响应时间。
实时进程的调度算法相对于普通进程更加严格,以满足实时性要求。
Linux内核的CPU调度基本原理是通过就绪队列、进程优先级和时间片轮转等策略,将CPU时间动态地分配给不同的进程或线程,以完成多任务处理。
linux核心函数Linux 内核是操作系统的核心部分,它提供了操作系统的核心功能,包括进程管理、内存管理、文件系统等。
Linux 内核的源代码中包含了大量的函数,用于实现各种操作系统的功能。
以下是一些Linux 内核中常见的核心函数,它们扮演着关键的角色:1.进程管理函数:–fork():创建一个新的进程。
–exec():在当前进程中执行一个新的程序。
–wait():等待子进程结束。
–exit():终止当前进程。
2.调度和任务管理函数:–schedule():进行进程调度。
–yield():主动让出CPU,将当前进程移动到就绪队列的末尾。
–wake_up_process():唤醒一个等待中的进程。
3.内存管理函数:–kmalloc():在内核中分配内存。
–kfree():释放内核中的内存。
–vmalloc():在虚拟地址空间中分配内存。
4.文件系统函数:–open():打开一个文件。
–read():从文件中读取数据。
–write():向文件中写入数据。
–close():关闭文件。
5.设备驱动函数:–register_chrdev():注册字符设备。
–unregister_chrdev():注销字符设备。
–request_irq():注册中断处理函数。
6.网络函数:–socket():创建套接字。
–bind():将套接字与地址绑定。
–listen():侦听传入连接请求。
–accept():接受传入的连接请求。
7.定时器和时钟函数:–timer_create():创建一个定时器。
–timer_settime():设置定时器的时间。
–gettimeofday():获取当前时间。
8.同步和互斥函数:–spin_lock():获取自旋锁。
–spin_unlock():释放自旋锁。
–mutex_lock():获取互斥锁。
–mutex_unlock():释放互斥锁。
这些函数仅仅是Linux 内核中众多函数的一小部分,Linux 内核的源代码非常庞大而复杂,包含了各种各样的功能和模块。
linux的malloc函数malloc是C 语言中的一个标准库函数,它用于在堆上动态分配内存。
在Linux 系统中,当你使用malloc时,你实际上是调用了 C 标准库中的这个函数。
这个函数是跨平台的,不仅限于Linux。
malloc的原型如下:cvoid *malloc(size_t size);其中,size参数指定要分配的字节数。
如果分配成功,malloc返回一个指向被分配内存的指针。
如果分配失败(例如,由于内存不足),则返回NULL。
使用malloc分配的内存块是未初始化的,即它们不包含任何特定的值。
如果你需要分配的内存块被初始化为0,可以使用calloc函数。
在使用完通过malloc分配的内存后,你应该使用free函数来释放它,以避免内存泄漏。
示例:c#include<stdio.h>#include<stdlib.h>int main() {int *ptr;size_t num = 10; // 分配10个整数的空间ptr = (int*)malloc(num * sizeof(int)); // 分配内存if (ptr == NULL) {printf("Memory allocation failed!\n");return1; // 返回错误代码}// 使用分配的内存...for (size_t i = 0; i < num; i++) {ptr[i] = i * i;}// 打印结果for (size_t i = 0; i < num; i++) {printf("%zu: %d\n", i, ptr[i]);}// 释放内存free(ptr);return0;}注意:在上面的示例中,我使用了类型转换(int*)来将malloc返回的void*指针转换为int*指针。
但在 C 语言中,当将void*赋值给其他类型的指针时,这种类型转换是自动的(在C++ 中则必须明确进行类型转换)。
devm_kzalloc函数devm_kzalloc函数是Linux内核中用来分配己映射内存的函数。
它是通过使用devres机制来进行资源管理的。
在这个函数被调用的时候,它会尝试为指定设备分配内存,并将其添加到设备的资源列表中,因此在设备被销毁时,这段内存会被自动释放。
以下是关于devm_kzalloc函数的详细解释。
void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)其中,dev是指向设备结构体的指针,size是要分配的内存大小,gfp指定了内存分配的标志。
devm_kzalloc函数使用了devres机制来管理内存资源。
devres是一个用于设备资源管理的机制,它允许将资源与设备进行绑定,以便在设备被解除绑定或销毁时自动释放。
通过使用devres机制,可以避免手动管理内存资源的复杂性。
```void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)void *ptr;struct devres *dr;ptr = kzalloc(size, gfp);if (!ptr)return NULL;dr = devres_alloc(devm_kfree, sizeof(struct devres));if (!dr)goto err_free_mem;dr->release = devm_kfree;dr->args[0] = ptr;devres_add(dev, dr);return ptr;err_free_mem:kfree(ptr);return NULL;```在函数内部,首先调用kzalloc函数来分配一段内存,并检查分配是否成功。
如果内存分配失败,则返回NULL。
然后,使用devres_alloc函数来分配一个devres结构体,并检查分配是否成功。
在Linux操作系统中,主存空间(内存)的分配和回收是由内核管理的。
当应用程序或系统需要更多的内存时,它们会向内核请求,内核会根据可用内存的情况来分配内存。
同样,当应用程序或系统不再需要某块内存时,它们会将其释放给内核,内核会将其回收以供将来使用。
1. 内存分配:
在Linux中,当一个进程需要更多的内存时,它会调用`malloc()`或`alloc()`等函数。
这些函数会向内核发送请求,要求分配一块指定的内存大小。
内核会查看当前可用内存的情况,并根据需要分配一块内存。
内核分配内存的过程包括以下几个步骤:
* 找到可用的物理内存页框。
* 将页框标记为已分配状态。
* 更新内存管理数据结构。
* 将页框地址返回给进程。
2. 内存回收:
当一个进程不再需要某块内存时,它会调用`free()`或`release()`等函数来释放该内存。
这些函数会将该内存标记为未分配状态,并通知内核回收该内存。
内核回收内存的过程包括以下几个步骤:
* 标记该页框为未分配状态。
* 更新内存管理数据结构。
* 如果该页框中有数据,则将其写回到磁盘或其他存储设备中。
* 将该页框标记为可用状态,以供将来使用。
需要注意的是,Linux采用了先进的内存管理技术,如分页和段页式管理,以及虚拟内存技术等,使得内存的分配和回收更加高效和灵活。
同时,Linux还具有强大的内存监控和管理工具,如`top`、`htop`、`free`等,可以帮助管理员监控和管理系统的内存使用情况。
以下是Linux系统下常用的C函数:
printf() -输出函数,常用于打印文本和变量值。
scanf() -输入函数,用于从键盘读取输入数据。
malloc() -内存分配函数,用于在堆上分配指定大小的内存空间。
free() -内存释放函数,用于释放先前分配的内存空间。
strcpy() -字符串复制函数,用于将一个字符串复制到另一个字符串中。
strlen() -字符串长度函数,用于计算一个字符串的长度。
strcmp() -字符串比较函数,用于比较两个字符串是否相等。
memset() -内存设置函数,用于将指定内存区域设置为指定的值。
memcpy() -内存复制函数,用于将一个内存区域的内容复制到另一个内存区域中。
fopen() -文件打开函数,用于打开一个文件以进行读写操作。
fclose() -文件关闭函数,用于关闭先前打开的文件。
fgets() -从文件中读取一行数据的函数。
fputs() -将一行数据写入文件的函数。
fprintf() -格式化输出到文件的函数,类似于printf()。
fscanf() -格式化输入从文件中读取数据的函数,类似于scanf()。
linux kerne malloc实现原理全文共四篇示例,供读者参考第一篇示例:Linux内核中的malloc实现原理是指Linux内核中用来分配内存空间的一种机制。
在Linux内核中,malloc的实现是通过内存分配器来完成的。
内存分配器是一个负责管理内存分配和释放的软件模块,通过调用内存分配器的接口函数,可以向程序分配内存以供其使用。
Linux内核中的内存分配器有多种实现方式,其中最常用的是slab 分配器和buddy系统。
这两种内存分配器分别适用于不同的场景,slab分配器主要用于小块内存的分配,而buddy系统则适用于大块内存的分配。
在实际使用中,malloc函数是用户空间程序调用的接口函数,其内部会根据一系列算法和数据结构来选择合适的内存分配器进行内存分配。
下面我们将详细介绍Linux内核中malloc的实现原理。
我们来看一下slab分配器的实现原理。
slab分配器是Linux内核中最基础的内存分配器,主要用于管理小块内存的分配。
slab分配器将内存划分为一系列的slab,每个slab包含一定数量的同样大小的内存块。
当程序请求分配内存时,slab分配器会从slab中选择一个空闲块分配给程序,并将该块从空闲块列表中移除。
slab分配器的实现原理是通过一系列的数据结构来管理slab和内存块的分配。
其中最重要的数据结构是slab描述符和slab页。
slab描述符是一个包含了slab地址、块大小和状态等信息的数据结构,用来描述一个slab的信息。
而slab页是一个记录了slab中每个内存块使用情况的数据结构,用来管理slab中内存块的分配和释放。
slab分配器还通过一系列的算法来实现内存的分配和回收。
当程序请求分配内存时,slab分配器会首先查找到一个合适的slab页,然后在该页中寻找一个空闲块分配给程序。
而当程序释放内存时,slab 分配器会将该内存块重新添加到空闲块列表中,以备下次分配时使用。
linux内存管理之vmalloc函数分析2017-07-09今天周末,闲来⽆事聊聊linux内核内存分配那点事……重点在于分析vmalloc的执⾏流程以传统x86架构为例,内核空间内存(3G-4G)主要分为三⼤部分:DMA映射区,⼀致映射区、⾼端内存区。
其中前两者占据低端892M,⽽剩下的128M作为⾼端内存区。
DMA映射区涉及到外部设备,咱们暂且不讨论,那么就剩下⼀致映射区和⾼端内存区。
⼀致映射区的虚拟地址均⼀⼀对应了物理页框,因此此区间虚拟地址的访问可以直接通过偏移量得到物理内存⽽不需进⾏页表的转换。
但是1G内核地址空间说实话有些捉襟见肘,如果都⽤作⼀致映射,那么当物理内存⼤于4G时,内核仍然⽆法利⽤。
鉴于此,留下128M的地址空间作为⾼端内存,扮演着临时映射的作⽤。
回想下PAE模式的原理,是不是有些相似呢?⼀致映射区既然都已经关联了物理内存就可以通过slab缓存来管理,以加速分配。
⽽⾼端内存这点有些类似于⽤户进程的内存分配,但⼜并不完全相同,后⾯咱们会讲到。
在这⾥咱们先回忆下⽤户空间内存分配流程,⼀个普通的进程调⽤malloc函数分配⼀段地址空间,有可能在堆中,如果内存过⼤海有可能在mmap映射区,同时会由⼀个vm_area_struct记录下本次分配出去的地址空间信息,如⼤⼩,起始地址等由于进程独享虚拟地址空间,所以这些vm_area_struct都是按照进程为单位进⾏管理的。
这也没⽑病。
此时仅仅是在进程管理虚拟内存的数据结构中记录了下这块虚拟地址空间被分配出去了,然⽽此时和物理内存还没管理,在真正发⽣读写的时候就会分配物理内存、填充页表。
然⽽在内核中,所有进程共享唯⼀的内核地址空间,所以内核地址空间需要统⼀管理。
下⾯我们根据源码分析下vmalloc的具体流程void *vmalloc(unsigned long size){return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);}该函数直接封装了__vmalloc_node,⽽__vmalloc_node⼜封装了__vmalloc_node_range,我们直接从__vmalloc_node_range函数看起void *__vmalloc_node_range(unsigned long size, unsigned long align,unsigned long start, unsigned long end, gfp_t gfp_mask,pgprot_t prot, int node, const void *caller){struct vm_struct *area;void *addr;unsigned long real_size = size;size = PAGE_ALIGN(size);if (!size || (size >> PAGE_SHIFT) > totalram_pages)goto fail;/*在⾼端内存区分配⼀个vm_struct并初始化*/area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNLIST,start, end, node, gfp_mask, caller);if (!area)goto fail;/*为area分配管理page的数组,并通过伙伴系统分配物理页⾯*/addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);if (!addr)return NULL;/** In this function, newly allocated vm_struct has VM_UNLIST flag.* It means that vm_struct is not fully initialized.* Now, it is fully initialized, so remove this flag here.*/clear_vm_unlist(area);/** A ref_count = 3 is needed because the vm_struct and vmap_area* structures allocated in the __get_vm_area_node() function contain* references to the virtual address of the vmalloc'ed block.*/kmemleak_alloc(addr, real_size, 3, gfp_mask);return addr;fail:warn_alloc_failed(gfp_mask, 0,"vmalloc: allocation failure: %lu bytes\n",real_size);return NULL;}前⾯说和⽤户空间进程分配内存类似的点就在于⾼端内存区的管理同样需要数据结构,和⽤户空间对应,内核使⽤vm_struct。
Linux内核的三种调度策略:1,SCHED_OTHER 分时调度策略,2,SCHED_FIFO实时调度策略,先到先服务。
一旦占用cpu则一直运行。
一直运行直到有更高优先级任务到达或自己放弃3,SCHED_RR实时调度策略,时间片轮转。
当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。
放在队列尾保证了所有具有相同优先级的RR任务的调度公平Linux线程优先级设置首先,可以通过以下两个函数来获得线程可以设置的最高和最低优先级,函数中的策略即上述三种策略的宏定义:int sched_get_priority_max(int policy);int sched_get_priority_min(int policy);SCHED_OTHER是不支持优先级使用的,而SCHED_FIFO和SCHED_RR支持优先级的使用,他们分别为1和99,数值越大优先级越高。
设置和获取优先级通过以下两个函数int pthread_attr_setschedparam(pthread_attr_t*attr,const struct sched_param *param);int pthread_attr_getschedparam(const pthread_attr_t*attr,struct sched_param *param); param.sched_priority = 51;//设置优先级系统创建线程时,默认的线程是SCHED_OTHER。
所以如果我们要改变线程的调度策略的话,可以通过下面的这个函数实现。
int pthread_attr_setschedpolicy(pthread_attr_t*attr,int policy);上面的param使用了下面的这个数据结构:struct sched_param{int __sched_priority;//所要设定的线程优先级};我们可以通过下面的测试程序来说明,我们自己使用的系统的支持的优先级:#include<stdio.h>#include<pthread.h>#include<sched.h>#include<assert.h>static int get_thread_policy(pthread_attr_t*attr){int policy;int rs =pthread_attr_getschedpolicy(attr,&policy);assert(rs==0);switch(policy){case SCHED_FIFO:printf("policy= SCHED_FIFO\n");break;case SCHED_RR:printf("policy= SCHED_RR");break;case SCHED_OTHER:printf("policy=SCHED_OTHER\n");break;default:printf("policy=UNKNOWN\n");break;}return policy;}static void show_thread_priority(pthread_attr_t*attr,int policy) {int priority = sched_get_priority_max(policy);assert(priority!=-1);printf("max_priority=%d\n",priority);priority= sched_get_priority_min(policy);assert(priority!=-1);printf("min_priority=%d\n",priority);}static int get_thread_priority(pthread_attr_t*attr){struct sched_param param;int rs =pthread_attr_getschedparam(attr,¶m); assert(rs==0);printf("priority=%d",param.__sched_priority);return param.__sched_priority;}static void set_thread_policy(pthread_attr_t*attr,int policy) {int rs =pthread_attr_setschedpolicy(attr,policy);assert(rs==0);get_thread_policy(attr);}int main(void){pthread_attr_t attr;struct sched_param sched;int rs;rs =pthread_attr_init(&attr);assert(rs==0);int policy = get_thread_policy(&attr);printf("Show current configuration of priority\n");show_thread_priority(&attr,policy);printf("show SCHED_FIFO of priority\n"); show_thread_priority(&attr,SCHED_FIFO);printf("show SCHED_RR of priority\n");show_thread_priority(&attr,SCHED_RR);printf("show priority of current thread\n");int priority = get_thread_priority(&attr);printf("Set thread policy\n");printf("set SCHED_FIFO policy\n");set_thread_policy(&attr,SCHED_FIFO);printf("set SCHED_RR policy\n");set_thread_policy(&attr,SCHED_RR);printf("Restore current policy\n");set_thread_policy(&attr,policy);rs =pthread_attr_destroy(&attr);assert(rs==0);return 0;}下面是测试程序的运行结果:policy=SCHED_OTHERShow current configuration of prioritymax_priority=0min_priority=0show SCHED_FIFO of prioritymax_priority=99min_priority=1show SCHED_RR of prioritymax_priority=99min_priority=1show priority of current threadpriority=0Set thread policyset SCHED_FIFO policypolicy= SCHED_FIFOset SCHED_RR policypolicy= SCHED_RRRestore current policypolicy=SCHED_OTHERLinux线程调度策略与优先级(二)上一篇文章介绍了Linux下的调度策略和优先级,在Ubuntu09.10上的一些特性,这里测试一下其中的两种特性,SCHED_OTHER和SCHED_RR,还有就是优先级的问题,是不是能够保证,高优先级的线程,就可以保证先运行。
kmem用法
kmem是一个Linux内核中用于分配内存的函数。
它提供了一种动态分配和释放内存的机制,用于管理系统中的内核内存。
准确用法:
kmem可以通过调用kmalloc函数来分配内核内存块。
kmalloc函数的原型如下:
void *kmalloc(size_t size, int flags);
其中,size参数是需要分配的内存块的大小,单位是字节;flags 参数是一个控制参数,用于指定分配内存时的行为。
拓展:
1. kmem的优势:
- kmem能够在内核空间中高效地进行内存分配和释放,比起用户空间的内存分配函数(如malloc)更加直接和快速。
- kmem分配的内存块是连续的,适合在驱动程序、内核模块等需要进行频繁读写的场景下使用。
- kmem的内存分配是以页作为单位进行的,有利于内存的管理和利用。
2. kmem的使用场景:
-驱动程序:驱动程序通常需要分配一些内核内存来存储驱动程序所需的数据结构、缓冲区等。
kmem可以方便地为驱动程序分配内存。
-内核模块开发:内核模块通常需要分配一些内存来存放模块的数据结构。
kmem可以满足内核模块在内核空间中进行内存分配的需求。
-物理页面管理:kmem可以用于物理页面的管理,比如分配和释放物理页面。
总之,kmem是一个非常有用的内核内存分配函数,可以方便地在内核空间中进行内存管理和分配。
它在Linux内核的开发和驱动程序开发中被广泛应用。
kzalloc函数
kzalloc函数是在Linux内核编程中广泛使用的一种函数,它的主要功能是分配
内存并初始化。
kzalloc函数的全称是Kernel Zero Allocate,即内核零分配。
kzalloc函数的特点是在申请到内核空间后,会自动把申请到的空间清零,所以使用该函数后,不需要再进行初始化操作。
这样就避免了一些因为内存未初始化
导致的问题,也因此在内核编程中广泛使用。
如果申请的空间过大,超过了连续的物理内存空间,可能导致kzalloc函数调用失败。
kzalloc函数的调用方式为:
其中,size是请求的内存大小,flags决定了分配内存的行为。
若分配成功,返回指向已分配内存的指针,若失败,则返回NULL。
kzalloc函数大小受限于内核空间的大小,在内核编程的过程中,我们需要注意控制好内存的使用,保证系统的稳定和效率。
kzalloc函数的使用可以大大简化和提高内核编程的效率,减少出错的可能性,对内核编程的学习和研究具有重要的参考价值。
在实际编程中,根据需要选择使用kmalloc或kzalloc函数分配内存。
如果对安全性要求较高,可以选择kzalloc函数,因为kzalloc会对分配的内存空间进行清零操作,避免了因为内存未初始化导致的
问题。
总的来说,kzalloc函数是内核编程中的一种非常重要的工具,由于其在内存分配和初始化方面的优秀表现,它为程序员提供了一种方便有效的编程工具。
内存映射函数remap_pfn_range学习——⽰例分析(2)作者彭东林QQ 405728433平台Linux-4.10.17Qemu-2.8 + vexpress-a9DDR:1GB概述前⾯分析了⽤kzalloc分配内核缓冲区并通过remap_pfn_range的⽅式将其映射到⽤户空间的⽰例,能否⽤其他⽅式分配内核缓冲区并映射到⽤户空间呢?当然可以,下⾯分别⽤alloc_pages和vmalloc来实现。
对应的驱动以及测试程序可以到下⾯的地址下载:正⽂⼀、⽤alloc_pages来实现alloc_pages的函数原型如下:1#define alloc_pages(gfp_mask, order) \2 alloc_pages_node(numa_node_id(), gfp_mask, order)34static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,5 unsigned int order)6 {7if (nid == NUMA_NO_NODE)8 nid = numa_mem_id();910return __alloc_pages_node(nid, gfp_mask, order);11 }它返回值的类型是struct page *,要获取对应的物理页帧或者虚拟地址的话,需要⽤专门的函数。
这个函数可以保证分配到的物理内存是连续的。
需要注意的是,如果是从低端内存分配出来的内存,在内核空间可以利⽤page_address()很容易的获取其对应的虚拟地址,但是如果是从⾼端内存区分配的内存,如果要在内核空间访问的话,需要先⽤kmap这样的函数将其映射到kmap区,然后才能访问。
但是对于remap_pfn_range来说就不⽤担⼼,只要保证要映射的size⼤⼩的空间对应物理地址是连续的就可以,alloc_pages可以满⾜。
[导读]Linux平台上几个常见内核内存分配函数
* kmalloc
Prototype:
#include
void *kmalloc(size_t size, int flags);
Kmalloc分配一段未清0的连续物理内存页,并返回虚存地址。
优点是快,并且可指定flag,如DMA内存,高地址区域内存等。
缺点是不能分配大于128KB(处于跨平台考虑),几个重要的flag:
GFP_ATOMIC
Used to allocate memory from interrupt handlers and other code outside of a process context. Never sleeps.
GFP_KERNEL
Normal allocation of kernel memory. May sleep.
GFP_USER
Used to allocate memory for user-space pages; it may sleep.
GFP_HIGHUSER
Like GFP_USER, but allocates from high memory, if any. High memory is described in the next subsection.
*__get_free_pages
Prototype:
_ _get_free_pages(unsigned int flags, unsigned int order);
返回2^order个未清0连续物理页面,flags与kmalloc中flags一致,允许的最大order
值为10或者11(根据体系结构不同)
*alloc_pages
Prototype:
struct page *alloc_pages_node(int nid, unsigned int flags,
unsigned int order);
Kernel中页分配器实现,__get_free_pages即调用alloc_pages实现的
The real core of the Linux page allocator is a function called alloc_pages_node:
*vmalloc
分配地址连续虚存,而不保证物理地址连续,大部分情况下适合“软件”,而不是驱动程序。
相对而言,kmalloc和__get_free_pages虚存map到物理内存只需要增减一个偏移,而使用vmalloc分配需要修改页表,故vmalloc的开销较大,分配少数几个页面的效率太低。
*per-cpu variables
Each cpu hold an independant copy in their respective processor's caches, so there is no lock required and improve better performance, implemented as a linux 2.6 feature. Defined in .
DEFINE_PER_CPU(type, name);
get_cpu_var(sockets_in_use)++;
put_cpu_var(sockets_in_use);
* slab allocator(lookaside cache)
从Memcached的实现知道有这么一个内存管理策略,其显着特点是分配一组相同大小的内存块作为内存池,其实现对应于源代码中的和mm/slab.c。
Prototype:
#include
kmem_cache_t *kmem_cache_create(char *name, size_t size, size_t offset,
unsigned long flags, constructor( ), destructor( ));
int kmem_cache_destroy(kmem_cache_t *cache);
/proc/slabinfo
A virtual file containing statistics on slab cache usage.
原文出自【比特网】,转载请保留原文链接:/126/11138126.shtml。