消耗内存

本文介绍如何使用Linux命令检查内存使用情况,包括free命令的基本用法及/proc/meminfo文件的内容解读。此外,还提供了两种内存消耗方法的示例:通过编写驱动程序memdev消耗内存,以及编写名为eatmem的应用程序进行内存消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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释放分配的内存,让内存恢复只要重启即可。


由于在内核中,kmalloc() 函数一共分配的最大范围为 760M左右,在内存还没有耗尽前,由于kmalloc() 本身的问题,达不到需要的目地。所以换另一种方法,写一个应用程序来消耗内存。


(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    //修改此进程的优先级,让它在内存过小时,不被杀死




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值