Linux基础篇之内存管理机制

转载这篇文章之前,先区分下缓存和缓冲的区别,

缓冲和缓存都是RAM中的数据。简单来说,buffer是即将要写入磁盘的数据,而cache是从磁盘中读取数据的。buffer是由各种进程分配的,被用在如输入队列等方面,一个简单的例子如某个进程要求有多个字段读入,在所有字段 被读入完整之前,进程把先前读入的字段放在buffer中保存。cache经常被用在磁盘的I/O请求上,如果有多个进程都要访问某个文件,于是该文件便被做成cache以方便下次被访问,这样可以提高系统性能。

1 Linux内存管理的主要特点

--------------------------------------------------------------------------------
无论物理内存多大,Linux都将其充分利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的数据访问性能。而Windows是只在需要内存时,才为应用程序分配内存,并不能充分利用大容量的内存空间。Linux的这一特性,主要是利用空闲的物理内存,划分出一部份空间,做为cache、buffers,以此提高数据访问性能。页面高速缓存(page cache)是Linux内核实现的一种主要磁盘缓存。它主要用来减少对磁盘的I/O操作。具体地讲,是通过把磁盘中的数据缓存到物理内存中,把对磁盘的访问变为对物理内存的访问。

2 物理内存、虚拟内存

--------------------------------------------------------------------------------
物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在Linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。
Linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。

Linux内存运行机制:
2.1 Linux系统会不时的进行页面交换操作,以保持尽可能多的空闲物理内存
2.2 Linux进行页面交换是有条件的,不是所有页面在不用时都交换到虚拟内存,Linux内核根据”最近最经常使用“算法,仅仅将一些不经常使用的页面文件交换到虚拟内存
2.3 交换空间的页面在使用时会首先被交换到物理内存,如果此时没有足够的物理内存来容纳这些页面,它们又会被马上交换出去

3 Linux内存监控

--------------------------------------------------------------------------------
free -m:
[root@rango  backup_CentOS]# free -m 
            total      used      free    shared    buffers    cached 
Mem:          3805      3683      121          0        120        690 
-/+ buffers/cache:      2872      932 
Swap:        2041        134      1907
注解:
total:    物理内存的总大小used:已经使用的物理内存大小free:空闲的物理内存大小
shared:    多个进程共享的内存大小buffers/cached:磁盘缓存的大小
Mem:    代表物理内存使用情况(-/+buffers/cached):代表磁盘缓存使用状态
Swap:    表示交换空间内存使用状态
(-buffers/cache) used内存数:2872M(指的第一部分Mem行中的used- buffers - cached)
(+buffers/cache) free内存数:  932M (指的第一部分Mem行中的free+ buffers + cached)
从内核的角度可使用的内存:121M
从应用程序可使用的内存:free+buffers/cache=121+120+690=931M,为第二行的free值。对于应用程序来说,buffers/cached占有的内存是可用的,因为buffers/cached是为了提高文件读取的性能,当应用程序需要用到内存的时候,buffers/cached会很快地被回收,以供应用程序使用。

Linux缓存机制:buffers与cached都是内存操作,用来保存系统曾经打开过的文件以及文件属性信息,这样当操作系统需要读取某些文件时,会首先在buffers与cached内存区查找,如果找到,直接读出传送给应用程序,如果没有找到需要数据,才从磁盘读取。
buffers是用来缓冲块设备做的,它只记录文件系统的元数据(metadata)以及tracking in-flightpages,而cached是用来给文件做缓冲。更通俗一点说:buffers主要用来存放目录里面有什么内容,文件的属性以及权限等等。而cached直接用来记忆我们打开过的文件和程序。

4  Linux内存释放过程

--------------------------------------------------------------------------------
4.1 free -m查看内存使用情况

4.2 sync:使用sync命令以确保文件系统的完整性,sync命令运行sync 子例程,将所有未写的系统缓冲区写到磁盘中,包含已修改的i-node、已延迟的块I/O和读写映射文件。为确保可靠起见,应执行两遍sync命令,这是因为sync命令完成时,并不保证信息实际写到了磁盘上。

4.3 修改/proc/sys/vm/drop_caches:
echo 3 > /proc/sys/vm/drop_caches
说明:
1)/proc是一个虚拟文件系统,我们可以通过对它的读写操作作为与kernel实体间进行通信的一种手段。也就是说可以通过修改/proc中的文件,来对当前kernel的行为做出调整。也就是说我们可以通过调整/proc/sys/vm/drop_caches来释放内存。
2)drop_caches:
Writing to this file causes the kernel to drop cleancaches,dentries and inodes from memory, causing that memory tobecomefree.
To free pagecache, use echo 1 > /proc/sys/vm/drop_caches;
to free dentries and inodes, use echo 2 >/proc/sys/vm/drop_caches;
to free pagecache, dentries and inodes, use echo 3>/proc/sys/vm/drop_caches.
Because this is a non-destructive operation and dirty objects arenot freeable, the user should run syncfirst.

5 Linux内存映射

--------------------------------------------------------------------------------
当可执行文件准备运行时,可执行文件的内容仅仅映射到了对应进程虚拟地址空间中,而并没有调入物理内存。当程序开始运行并使用到这部分时,Linux才通过缺页中断把它们从磁盘上调入内存。这种将文件连接到进程虚拟地址空间的过程称为内存映射。
一般情况下,用户空间是不可能也不应该直接访问设备的,但是,设备驱动程序中可实现mmap()函数,这个函数可使得用户空间能直接访问设备的物理地址。实际上,mmap()实现了这样的一个映射过程,它将用户空间的一段内存与设备内存关联,当用户访问用户空间的这段地址范围时,实际上会转化为对设备的访问。
当用户调用mmap()的时候,内核会进行如下的处理:
① 在进程的虚拟空间查找一块VMA。
② 将这块VMA进行映射。
③ 如果设备驱动程序或者文件系统的file_operations定义了mmap()操作,则调用它。
④ 将这个VMA插入进程的VMA链表中。
vma包含了用于访问设备的虚拟地址的信息,因此大量的工作由内核完成。为了执行mmap,驱动程序只需要为该地址返回建立合适的页表,并将vma->vm_ops替换为一系列的新操作就可以了。

6 Linux共享内存

--------------------------------------------------------------------------------
6.1 共享内存

--------------------------------------------------------------------------------
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。

采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。

6.2 共享内存的释放

--------------------------------------------------------------------------------
在使用共享内存的程序异常退出时,由于没有释放掉共享内存,在调试时会出现错误。
释放共享内存的方法:
1)如果总是通过Crtl+C来结束的话,可以做一个信号处理器,当接收到这个信号的时候,先释放共享内存,然后退出程序。
2)通过linux命令ipcrm shm shmid来释放,在使用该命令之前可以通过ipcs -m命令来查看共享内存。
查看共享内存:ipcs -m          -m只显示共享内存信息,-q只显示消息队列,-s只显示信号量
[root@rango  backup_CentOS]# ipcs -m

------ Shared Memory Segments -------- 
key        shmid      owner      perms    bytes      nattch    status      
0x00000000 98304      rango      600      393216    2          dest        
0x00000000 131073    rango      600      393216    2          dest        
0x00000000 163842    rango      600      393216    2          dest        
0x00000000 196611    rango      600      393216    2          dest        
0x00000000 229380    rango      600      393216    2          dest        
0x00000000 262149    rango      600      393216    2          dest        
0x00000000 294918    rango      600      393216    2          dest        
0x00000000 327687    rango      600      393216    2          dest        
0x00000000 360456    rango      600      393216    2          dest
第一列就是共享内存的key;        第二列是共享内存的编号shmid;
第三列就是创建的用户owner;    第四列就是权限perms;
第五列为创建的大小bytes;        第六列为连接到共享内存的进程数nattach;
第七列是共享内存的状态status。其中显示“dest”表示共享内存段已经被删除,但是还有用户在使用它,当该段内存的mode字段设置为SHM_DEST时就会显示“dest”。当用户调用shmctl的IPC_RMID时,内存先查看多少个进程与这个内存关联着,如果关联数为0,就会销毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,如果所有进程都不用则删除这段共享内存。

释放共享内存:ipcrm <shmid>  #释放单个共享内存
ipcs -m | awk ‘$2 ~/[0-9]+/ {print$2}’ | while read s; do sudo ipcrm –m $s; done  #释放所有共享内存
ps:释放共享内存的python脚本

rmsharemem.py
#!/usr/bin/env python 
# Description: Remove the share memory 
# Author: RangoChen 
# Date: 2013.12.19
# -*- coding: utf-8 -*-
# Remove the share memory
import os
import sys
import getopt

def usage():
  print "usage: python rmsharemem.py -h -o <owner> -ssize <shmid list>"
  print " -h show help information"
  print " -o <owner> the owner create share memory needto delete"
  print " -s <size> the share memory size"
  print " <shmid list> the shmid list need to delete"

def getsharemem():
  sharemap = {}
  fp = os.popen(‘ipcs -m‘)
  lines = fp.readlines()
  for l in lines:
      if not l.startswith(‘0x‘):
          continue
  s = l.split()
  if sharemap.has_key(s[2]):
      sharemap[s[2]].append(s)
  else:
        sharemap[s[2]] = [s]
  #print ‘Share memory map:\n‘, sharemap
return sharemap

if __name__ == "__main__":
  opts, args = getopt.getopt(sys.argv[1:], "o:hs:")
    # opts is the parameter with options
  # args is the parameter no ptions
    owner = None
    size = 0
  for o, p in opts:
      if o == ‘-h‘:
      usage()
      sys.exit(0)
  elif o == ‘-o‘:
      owner = p
  elif o == ‘-s‘:
      size = p

if not owner:
  val = raw_input("Are you sure to remove all sharememory?(yes/no)")
  if (val == "yes"):
      usage()
      sys.exit(0)

count = 0
total = 0
if len(args) > 0:
    for shmid in args:
        cmd = ‘ipcrm -m %s‘ % shmid
      print ‘execute command: %s‘ % cmd
        ret = os.system(cmd)
        total += 1
      if ret == 0:
            count += 1
            print ‘remove %s shared memory success‘ % shmid
      else:
          print ‘remove %s shared memory failed‘ % shmid
  else:
      shmmap = getsharemem()
      for o, l in shmmap.items():
          if owner and o == owner:
              continue
      for p in l:
            total += 1
            if size and size == p[4]:
                continue
          cmd = ‘ipcrm -m %s‘ % p[1]
          print ‘execute command: %s‘ % cmd
          ret = os.system(cmd)
          if ret == 0:
                count += 1
              print ‘remove %s shared memory success‘ % p[1]
          else:
              print ‘remove %s shared memory failed‘ % p[1]
print ‘total share memory number = %s‘ % total
print ‘remove success number = %s‘ % count
sys.exit(0)

6.3 共享内存大小的修改

--------------------------------------------------------------------------------
查看共享内存的大小:cat    /proc/sys/kernel/shmmax
临时修改:echo 268435456 > /proc/sys/kernel/shmmax#把共享内存大小设置为256MB;
永久修改:vim /etc/rc.d/rc.local:  echo 268435456 > /proc/sys/kernel/shmmax
即可每次启动时把共享内存修改为256MB.

7 总结

--------------------------------------------------------------------------------
此文介绍了Linux内存管理机制,包括内存映射、共享内存的实现机制等。

时间: 2024-10-09 13:54:00

Linux基础篇之内存管理机制的相关文章

Linux内存管理机制

一.首先大概了解一下计算机CPU.Cache.内存.硬盘之间的关系及区别. 1.  CPU也称为中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路, 是一台计算机的运算核心(Core)和控制核心( Control Unit).它的功能主要是解释计算机指令以及处理计算机软件中的数据.中央处理器主要由三核心部件组成,运算器.控制器和总线(BUS),运算器又主要由算术逻辑单元(ALU)和寄存器(RS)组成. 2.Cache即高速缓冲存储器,是位于CPU与主内存

浅谈Linux内存管理机制

经常遇到一些刚接触Linux的新手会问内存占用怎么那么多? 在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这方面,区别于Windows的内存管理.主要特点是,无论物理内存有多大,Linux 都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的数据访问性能.而Windows是只在需要内存时,才为应用程序分配内存,并不能充分利用大容量的内存空间.换句话说,每增加一

Linux内存管理机制简介

在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,区别于 Windows的内存管理. 主要特点是,无论物理内存有多大,Linux 都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的数据访问性能.而Windows 是只在需要内存时,才为应用程序分配内存,并不能充分利用大容量的内存空间.换句话说,Linux自身的预分配内存机制使得主机上的物理内存会全部被用上.每增加一

【研究任务】linux内存管理机制——内核空间

Linux内存中线性地址为4G,0~3G为用户空间,3~4G为内核空间 一.      内核空间 内核空间是3~4G的内存地址,主要用来存储高优先级的代码 在X86结构中的内核地址存在三种类型的区域: ZONE_DMA     内存开始的16m ZONE_NORMAL       16m~896m ZONE_HIGHMEM    896M~ ZONE_DMA是DMA使用的页(DMA是直接路径访问,不经过cpu缓存而直接访问内存)ZONE_NORMAL是正常可寻址的页.ZONE_HIGHMEM是动

32位机内存管理机制(上)

一直有看linux内核的冲动,内核有些部分是汇编编写的,无奈汇编不大懂,所以利用五一三天假期大概走了一边8086CPU架构的汇编,8086CPU还是16位的,我们现在都进入64位时代了,这两者之间有很大的区别,但是看看16位的CPU汇编还是很重要的,这有助于理解32位的80386CPU.这篇文章来分析下80386的内存管理的一些基础知识,包括实模式.保护模式和内存寻址等等. 1.实模式 处理器被复位或者加电的时候以实模式启动.这时候处理器中各寄存器以实模式的初始化值工作. 80386处理器在实模

轻量级操作系统FreeRTOS的内存管理机制(三)

本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 轻量级操作系统FreeRTOS的内存管理机制(二)中讲到,heap2.c的内存管理机制会导致内存碎片的问题,系统运行久后会出现无法分配大块内存的情况,heap4.c中的管理机制提供了解决方法,它是在heap2.c的基础上添加了地址相邻空闲块间合并的功能,而heap5.c是对heap4.c的进一步扩展,它能够支持多块不连续分布的RAM空间作为堆使用,本篇将对heap4.c.heap5.c中的管理机制进行分析. 一.heap4.c

轻量级操作系统FreeRTOS的内存管理机制(二)

本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 上一篇文章中介绍了FreeRTOS多种内存管理机制中最简单的一种:全局声明一个静态数组ucHeap,然后通过指针偏移记录空间的分配情况,在这种内存机制下无法对内存进行释放.同时也介绍了内存操作过程中字节对齐的细节,本篇文章将会对FreeRTOS源码中第二种内存管理机制heap2.c进行讲解,在heap2.c中同样使用一个全局静态数组ucHeap来表示内存,heap2.c内存管理机制较heap1.c而言增加了内存释放的功能,通过使

&lt;Linux内核源码&gt;内存管理模型

题外语:本人对linux内核的了解尚浅,如果有差池欢迎指正,也欢迎提问交流! 首先要理解一下每一个进程是如何维护自己独立的寻址空间的,我的电脑里呢是8G内存空间.了解过的朋友应该都知道这是虚拟内存技术解决的这个问题,然而再linux中具体是怎样的模型解决的操作系统的这个设计需求的呢,让我们从linux源码的片段开始看吧!(以下内核源码均来自fedora21 64位系统的fc-3.19.3版本内核) <include/linux/mm_type.h>中对于物理页面的定义struct page,也

Linux内核工程导论——内存管理(一)

Linux内存管理 概要 物理地址管理 很多小型操作系统,例如eCos,vxworks等嵌入式系统,程序中所采用的地址就是实际的物理地址.这里所说的物理地址是CPU所能见到的地址,至于这个地址如何映射到CPU的物理空间的,映射到哪里的,这取决于CPU的种类(例如mips或arm),一般是由硬件完成的.对于软件来说,启动时CPU就能看到一片物理地址.但是一般比嵌入式大一点的系统,刚启动时看到的已经映射到CPU空间的地址并不是全部的可用地址,需要用软件去想办法映射可用的物理存储资源到CPU地址空间.