1. 了解如何查看linux下内存的使用
Linux中使用free可以查看系统内存使用状态, 默认单位为 kB
blue_stone@blueice:~$ free
total used free shared buffers cached
Mem: 2075320 1879172 196148 0 533484 952588
-/+ buffers/cache: 393100 1682220
Swap: 2008084 0 2008084
Mem 行显示了从系统角度看来内存使用的情况, total是系统可用的内存大小, 数量上等于系统物理内存减去内核保留的内存. buffers和cached是系统用做缓冲的内存. buffers与
某个块设备关联, 包含了文件系统元数据, 并且跟踪了块的变化. cache只包含了文件本身.
-/+ buffers/cache行则从用户角度显示内存信息, 可用内存从数量上等于mem行used列值减去buffers和cached内存的大小. 因为buffers和cached是操作系统为加快系统运行而
设置的, 当用户需要时, 可以只接为用户使用.
cat /proc/meminfo中读取内存信息.
进程使用的内存可以用top, ps来查看
注:linux中命令 df 是查看各个目录的使用情况
2. 了解内存的消耗的方法
可以使用两种方法: 1) 编写一个消耗内存的驱动memdev;
2)写一个消耗内存的应用程序;
1)消耗内存驱动memdev
在文件夹memdev中创建如下文件
vim memdev.h
//定义一个适合memdev使用的结构体
#ifndef _MEMDEV_H_
#define _MEMDEV_H_
#ifndef MEMDEV_MAJOR
#define MEMDEV_MAJOR 0 /*预设的mem的主设备号*/
#endif
#ifndef MEMDEV_NR_DEVS
#define MEMDEV_NR_DEVS 1 /*设备数*/
#endif
#ifndef MEMDEV_SIZE
#define MEMDEV_SIZE 4096
#endif
/*mem设备描述结构体*/
struct mem_dev
{
struct cdev cdev;
unsigned char data[MEMDEV_SIZE];
};
#endif /* _MEMDEV_H_ */
vim memdev.c
/*
*filename: memdev.c
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/seq_file.h>
#include <linux/fcntl.h>
#include <linux/seq_file.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "memdev.h"
static int mem_major = MEMDEV_MAJOR; //预定义
struct mem_dev *mem_devp; /*设备结构体指针*/
struct class *memdev_class;
/*文件打开函数*/
int mem_open(struct inode *inode, struct file *filp)
{
filp->private_data = mem_devp;//把设备结构体赋给filep的私有数据
return 0;
}
/*文件释放函数*/
int mem_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*读函数*/
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
if (p >= MEMDEV_SIZE)
return 0;
if(count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p;
if (copy_to_user(buf, dev->data + p, count)) //从内核到用户空间
return -EFAULT;
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "~~~~read %d bytes(s) from %ld\n", count, p);
}
return ret;
}
/*写函数*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0, i;
int num = 0; /*保存用户数据的整数形式*/
unsigned char *chr = NULL; /*获取用户写入的数据*/
char *test = NULL; /*判断kmalloc()分配的空间是否成功*/
struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= MEMDEV_SIZE)
return 0;
if (count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p;
/*从用户空间写入数据*/
printk(KERN_INFO "%p,%p\n",dev->data, dev->data+1 );
if (copy_from_user(dev->data + p, buf, count))
ret = - EFAULT;
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "written %d bytes(s) from %ld\n", count, p);
}
chr = dev->data;
printk(KERN_INFO "~~~~~~input string %s\n", chr);
while(*chr != '\n')
{
num = num*10 +(*chr - 48);
chr = chr + 1;
}
printk(KERN_INFO "~~~~~~num = %d \n", num);
#if 1
count = 0;
for(i=0; i < num * 1024; i++)
{
test = kmalloc(1024*sizeof(char), GFP_KERNEL);
if (!test) /*申请失败*/
{
printk(KERN_INFO "ERROR: kmalloc fail,memory is small !\n");
break;
}
memset(test, 0, 1024*sizeof(char));
count += 1;
}
printk(KERN_INFO "kmalloc %d kB.\n", count);
#endif
return ret;
}
/*文件操作结构体*/
static const struct file_operations mem_fops =
{
.owner = THIS_MODULE,
.read = mem_read,
.write = mem_write,
.open = mem_open,
.release = mem_release,
};
/*设备驱动模块加载函数*/
static int memdev_init(void)
{
int result;
dev_t devno = MKDEV(mem_major, 0);
/* 静态申请设备号*/
if (mem_major)
result = register_chrdev_region(devno, 1, "memdev");
else /* 动态分配设备号 */
{
result = alloc_chrdev_region(&devno, 0, 1, "memdev");
mem_major = MAJOR(devno);
}
if (result < 0)
{
printk(KERN_WARNING "memdev: can't get major %d \n", mem_major);
return result;
}
//重新获取设备号
devno = MKDEV(mem_major, 0);
/* 为设备描述结构分配内存*/
mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
if (!mem_devp) /*申请失败*/
{
result = - ENOMEM;
goto fail_malloc;
}
memset(mem_devp, 0, sizeof(struct mem_dev));
/*初始化cdev结构*/
cdev_init(&mem_devp->cdev, &mem_fops);
mem_devp->cdev.owner = THIS_MODULE;
mem_devp->cdev.ops = &mem_fops;
/* 注册字符设备 */
result = cdev_add(&mem_devp->cdev, devno, 1);
if(result)
{
printk(KERN_NOTICE "Error %d adding memdev", result);
}
#if 1
memdev_class = class_create(THIS_MODULE, "memdev");
if(IS_ERR(memdev_class))
{
result = PTR_ERR(memdev_class);
goto out_cdev;
}
device_create(memdev_class, NULL, devno, NULL, "memdev");
#endif
printk("memdev is OK !");
return 0;
out_cdev:
cdev_del(&mem_devp->cdev);
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
/*模块卸载函数*/
static void memdev_exit(void)
{
#if 1
device_destroy(memdev_class, MKDEV(mem_major, 0));
class_destroy(memdev_class);
#endif
cdev_del(&mem_devp->cdev); /*注销设备*/
kfree(mem_devp); /*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(mem_major, 0), 1); /*释放设备号*/
printk(" memdev Goodbye ! ");
}
MODULE_LICENSE("Dual BSD/GPL");
module_init(memdev_init);
module_exit(memdev_exit);
Makefile
#
#Makefile for the memdev drivers
#
#放在系统内部编译只要这一句话就可以
#obj-$(CONFIG_MEMDEV_MODULE) += memdev.o
# 单独编译成模块
# call from kernel build system
ifneq ($(KERNELRELEASE),)
obj-m := memdev.o
else
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY:clean
Kconfig
#
#filename: Kconfig
#
config MEMDEV_MODULE
tristate "memdev module support"
default m
在目录memdev下执行
$ make //获得memdev.ko模块
$ insmod memdev.ko //加载模块
$ ls /dev/ //查看驱动是否加载上
$ echo "100" > /dev/memdev //分配100MB的内存
注:此驱动函数在write函数中,只进行了kmalloc分配内存,并没有用函数free释放分配的内存,让内存恢复只要重启即可。
(2) 应用程序
/*
* date: 2014-04-17
* filename: eatmem.c
* describe: Memory consumption
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <memory.h>
int main (int argc, char** argv)
{
char *psize;
int size;
if( 2 == argc )
{
//字符串转整型
size = atoi(argv[1]);
printf(" the size is %d \n", size);
}
else{
printf(" Usage: eatmem <size> \n");
return -1;
}
int i = 0;
for(i = 0; i < size; i++){
psize = (char*)malloc(1024*1024*sizeof(char)); //分配 1M 的内存
if(psize == NULL)
{
printf("ERROR: malloc fail !! \t");
printf("Allocated the memory %dM\n", i);
continue;
}
else
memset(psize, 0, 1024*1024*sizeof(char)); //将分配到的内存全部写入数据,确保分配的都已使用
psize = NULL;
}
printf("Allocated the memory %dM\n", size);
while(1)
sleep(10); //让函数不结束,函数运行到return 0就会把所分配的内存都释放,达不到目的
return 0;
}
在eatmem.c 文件目录下执行
$ gcc eatmem.c -o eatmem -m32 -static //-m32表示编译为32位机器使用,-static 链接静态库
$ ./eatmem 100 & //分配100M的内存,并且在后台执行
$ ps //查找 ./eatmem 进程的进程号xxx
$ cd /proc/xxx
$ cat -17 > oom_adj //修改此进程的优先级,让它在内存过小时,不被杀死