引用文章
- Linux阅马场
- 初探Linux内核态——通过proc文件系统作快速问题定位
- linux通过meminfo 与 slab 定位内存泄漏
- 曾文斌: /proc/meminfo之谜完全揭秘
- vmalloc与mmap
- FREE命令显示的BUFFERS与CACHED的区别
- Linux ate my ram
- mm_struct简介
- 详细讲解从用户空间申请内存到内核如何为其分配内存的过程
- Linux进程地址管理之mm_struct
- Linux Memory Mapping--mmap kernel 2.6
- 郭健: Linux内存模型——平坦、非连续与稀疏
- 郝健: Linux内存管理学习笔记
- 郝健: Linux内存管理学习笔记-第1课
- 第二课
- 第三课
- 第四课
- 第五课
- 第六课
- 陈延伟:任督二脉之内存管理总结笔记
- 宋宝华:Linux内核的连续内存分配器(CMA)——避免预留大块内存
- 宋宝华: Linux mmap的多种情况和背后的差异
- 避免物理内存碎片化
- 宋宝华:Linux的任督二脉——进程调度和内存管理
- 宋宝华: CPU是如何访问到内存的?--MMU最基本原理
- 宋牧春: Linux内核slab内存的越界检查——SLUB_DEBUG
- 宋牧春: 多图详解Linux内存分配器slub
- 多核心Linux内核路径优化的不二法门之-slab与伙伴系统
- 宋宝华: 关于DMA ZONE和dma alloc coherent若干误解的彻底澄清
- 又是一年三月三:Linux的任督二脉之内存管理直播
- linux 内存管理初探
- 进程内存管理初探
- 宋宝华:网上坑爹的Linux资料汇总之内存管理
- 宋宝华: Linux为什么一定要copy_from_user ?
- 宋宝华:swappiness=0究竟意味着什么?
- 为什么手工drop_caches之后cache值并未减少?
一. 用户进程内存管理
1.1 进程的虚拟地址空间VMA
1.2 进程的pmap
1.3 VMA与程序的各个段以及库关系
1.4 VSS, RSS, PSS, USS的关系
1.5 page fault的几种可能性
1.6 进程内存泄漏的界定
1.7 内存泄漏的检查
二. 内核内存管理
2.1 内存分布
2.2 内存管理图
三. 用户空间和内核空间内存分配关系
3.1 内存总体关系图
3.2 Libc, Slab与buddy
3.3 kmalloc VS vmalloc/ioremap
四. 一个mmap的小实验
4.1 kernel driver
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <asm/io.h>
#include <linux/device.h>
/* length of the two memory areas */
#define NPAGES 16
struct mmap_dev_info_st {
/* char device */
dev_t mmap_dev;
struct cdev mmap_cdev;
struct class *mmap_class;
/* pointer to the vmalloc'd area - alway page aligned */
int *vmalloc_area;
/* pointer to the kmalloc'd area, rounded up to a page boundary */
int *kmalloc_area;
/* original pointer for kmalloc'd area as returned by kmalloc */
void *kmalloc_ptr;
};
static struct mmap_dev_info_st mmap_dev_info;
static int mmap_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int mmap_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* mmap's the kmalloc'd area which is physically contiguous */
int mmap_kmem(struct file *filp, struct vm_area_struct *vma)
{
int ret = 0;
long length = vma->vm_end - vma->vm_start;
int *kmalloc_area = mmap_dev_info.kmalloc_area;
printk(KERN_ERR "%s: start\n", __func__);
/* check length - do not allow larger mappings than the number of
pages allocated */
if (length > NPAGES * PAGE_SIZE) {
ret = -EIO;
printk(KERN_ERR "%s: length err.\n", __func__);
goto err;
}
/* map the whole physically contiguous area in one piece */
ret = remap_pfn_range(vma, vma->vm_start,
virt_to_phys((void *)kmalloc_area) >> PAGE_SHIFT,
length, vma->vm_page_prot);
if (ret < 0) {
printk(KERN_ERR "%s: ret:%d err.\n", __func__, ret);
goto err;
}
return 0;
err:
return ret;
}
/* mmap's the vmalloc'd area which is not physically contiguous */
int mmap_vmem(struct file *filp, struct vm_area_struct *vma)
{
int ret = 0;
long length = vma->vm_end - vma->vm_start;
unsigned long start = vma->vm_start;
char *vmalloc_area_ptr = (char *)mmap_dev_info.vmalloc_area;
unsigned long pfn = 0;
printk(KERN_ERR "%s: start\n", __func__);
/* check length - do not allow larger mappings than the number of
pages allocated */
if (length > NPAGES * PAGE_SIZE) {
ret = -EIO;
printk(KERN_ERR "%s: length err.\n", __func__);
goto err;
}
/* loop over all pages, map it page individually */
while (length > 0) {
pfn = vmalloc_to_pfn(vmalloc_area_ptr);
ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED);
if (ret < 0) {
printk(KERN_ERR "%s: remap_pfn_range err.\n", __func__);
goto err;
}
start += PAGE_SIZE;
vmalloc_area_ptr += PAGE_SIZE;
length -= PAGE_SIZE;
}
return 0;
err:
return ret;
}
/* character device mmap method */
static int mmap_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret = 0;
if (vma->vm_pgoff == 0) {
/* at offset 0 we map the vmalloc'd area */
ret = mmap_vmem(filp, vma);
} else if (vma->vm_pgoff == NPAGES) {
/* at offset NPAGES we map the kmalloc'd area */
ret = mmap_kmem(filp, vma);
} else {
/* at any other offset we return an error */
ret = -EIO;
}
return ret;
}
static struct file_operations mmap_fops = {
.open = mmap_open,
.release = mmap_release,
.mmap = mmap_mmap,
.owner = THIS_MODULE,
};
static int __init my_mmap_init(void)
{
int ret = 0;
int i = 0;
printk(KERN_ERR "%s: start\n", __func__);
/* allocate a memory area with kmalloc. Will be rounded up to a page boundary */
if ((mmap_dev_info.kmalloc_ptr = kmalloc((NPAGES + 2) * PAGE_SIZE, GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
goto out;
}
/* round it up to the page bondary,即找到页对齐的地址 */
mmap_dev_info.kmalloc_area = (int *)PAGE_ALIGN((unsigned long)mmap_dev_info.kmalloc_ptr);
/* allocate a memory area with vmalloc. */
if ((mmap_dev_info.vmalloc_area = (int *)vmalloc(NPAGES * PAGE_SIZE)) == NULL) {
ret = -ENOMEM;
goto out_kfree;
}
/* get the major number of the character device */
if ((ret = alloc_chrdev_region(&mmap_dev_info.mmap_dev, 0, 1, "mmap")) < 0) {
printk(KERN_ERR "could not allocate major number for mmap\n");
goto out_vfree;
}
/* initialize the device structure and register the device with the kernel */
cdev_init(&mmap_dev_info.mmap_cdev, &mmap_fops);
if ((ret = cdev_add(&mmap_dev_info.mmap_cdev, mmap_dev_info.mmap_dev, 1)) < 0) {
printk(KERN_ERR "could not allocate chrdev for mmap\n");
goto out_unalloc_region;
}
/* mark the pages reserved,即让申请的memory不被交换到磁盘。*/
for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE) {
//mark_page_reserved(vmalloc_to_page((void *)(((unsigned long)(mmap_dev_info.vmalloc_area)) + i)));
//mark_page_reserved(virt_to_page(((unsigned long)(mmap_dev_info.kmalloc_area)) + i));
SetPageReserved(vmalloc_to_page((void *)(((unsigned long)(mmap_dev_info.vmalloc_area)) + i)));
SetPageReserved(virt_to_page(((unsigned long)(mmap_dev_info.kmalloc_area)) + i));
}
/* store a pattern in the memory - the test application will check for it */
for (i = 0; i < (NPAGES * PAGE_SIZE / sizeof(int)); i += 2) {
mmap_dev_info.vmalloc_area[i] = (0xaffe << 16) + i;
mmap_dev_info.vmalloc_area[i + 1] = (0xbeef << 16) + i;
mmap_dev_info.kmalloc_area[i] = (0xdead << 16) + i;
mmap_dev_info.kmalloc_area[i + 1] = (0xbeef << 16) + i;
}
/* create class */
mmap_dev_info.mmap_class = class_create(THIS_MODULE, "mmap_class");
if (IS_ERR(mmap_dev_info.mmap_class)) {
printk(KERN_ERR "class_create failed.\n");
ret = -1;
goto out_unalloc_region;
}
/* create device */
device_create(mmap_dev_info.mmap_class, NULL, mmap_dev_info.mmap_dev, NULL, "mmap_dev");
printk(KERN_ERR "%s: end\n", __func__);
return ret;
out_unalloc_region:
unregister_chrdev_region(mmap_dev_info.mmap_dev, 1);
out_vfree:
vfree(mmap_dev_info.vmalloc_area);
mmap_dev_info.vmalloc_area = NULL;
out_kfree:
kfree(mmap_dev_info.kmalloc_ptr);
mmap_dev_info.kmalloc_ptr = NULL;
out:
return ret;
}
static void __exit my_mmap_exit(void)
{
int i = 0;
/* unregister device */
device_destroy(mmap_dev_info.mmap_class, mmap_dev_info.mmap_dev);
/* remove the character deivce */
cdev_del(&(mmap_dev_info.mmap_cdev));
class_destroy(mmap_dev_info.mmap_class);
unregister_chrdev_region(mmap_dev_info.mmap_dev, 1);
/* unreserve the pages */
for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE) {
//free_reserved_page(vmalloc_to_page((void *)(((unsigned long)(mmap_dev_info.vmalloc_area)) + i)));
//free_reserved_page(virt_to_page(((unsigned long)(mmap_dev_info.kmalloc_area)) + i));
ClearPageReserved(vmalloc_to_page((void *)(((unsigned long)(mmap_dev_info.vmalloc_area)) + i)));
ClearPageReserved(virt_to_page(((unsigned long)(mmap_dev_info.kmalloc_area)) + i));
}
/* free the memory areas */
if (mmap_dev_info.vmalloc_area) {
vfree(mmap_dev_info.vmalloc_area);
mmap_dev_info.vmalloc_area = NULL;
}
if (mmap_dev_info.kmalloc_ptr) {
kfree(mmap_dev_info.kmalloc_ptr);
mmap_dev_info.kmalloc_ptr = NULL;
}
}
module_init(my_mmap_init);
module_exit(my_mmap_exit);
MODULE_DESCRIPTION("mmap demo driver");
MODULE_AUTHOR("vector");
MODULE_LICENSE("GPL");
ifneq ($(KERNELRELEASE),)
obj-m := map_driver.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif
4.2 userspace test app
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#define LEN (16*4096)
int main(int argc, void **argv)
{
int i = 0;
int fd;
unsigned int *vadr;
fd = open("/dev/mmap_dev", O_RDWR);
if (fd < 0) {
perror("open");
return -1;
}
vadr = mmap(0, LEN, PROT_READ, MAP_SHARED, fd, 0);
if (vadr == MAP_FAILED) {
perror("mmap");
return -1;
}
printf("------------------------------------------------");
for (i = 0; i < (LEN / 4); i++) {
printf("0x%08x,", *(vadr + i));
if ((i % 10) == 0)
printf("\n");
}
close(fd);
return(0);
}