http://blog.csdn.net/dyllove98/article/details/8917197

Linux对于内存的管理涉及到非常多的方面,这篇文章首先从对进程虚拟地址空间的管理说起。(所依据的代码是2.6.32.60)

无论是内核线程还是用户进程,对于内核来说,无非都是 task_struct这个数据结构的一个实例而已,task_struct被称为进程描述符(process descriptor),因为它记录了这个进程所有的context。其中有一个被称为'内存描述符‘(memory descriptor)的数据结构 mm_struct,抽象并描述了Linux视角下管理进程地址空间的所有信息。
mm_struct定义在include/linux/mm_types.h中,其中的域抽象了进程的地址空间,如下图所示:
 
 
 
每个进程都有自己独立的mm_struct,使得每个进程都有一个抽象的平坦的独立的32或64位地址空间,各个进程都在各自的地址空间中相同的地址内存存放不同的数据而且互不干扰。如果进程之间共享相同的地址空间,则被称为线程
其中[start_code,end_code)表示代码段的地址空间范围。
[start_data,end_start)表示数据段的地址空间范围。
[start_brk,brk)分别表示heap段的起始空间和当前的heap指针。
[start_stack,end_stack)表示stack段的地址空间范围。
mmap_base表示memory mapping段的起始地址。 那为什么mmap段没有结束的地址呢?
bbs段是用来干什么的呢?bbs表示的所有没有初始化的全局变量,这样只需要将它们匿名映射为‘零页’,而不用在程序load过程中从磁盘文件显示的mapping,这样既减少了elf二进制文件的大小,也提高了程序加载的效率。 在mm_struct中为什么没有bbs段的地址空间表示呢?
 
除此之外,mm_struct还定义了几个重要的域:
 215        atomic_t mm_users;                      /* How many users with user space? */
216 atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */

这两个counter乍看好像差不多,那Linux使用中有什么区别呢?看代码就是最好的解释了。

 681static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
682{
683 struct mm_struct * mm, *oldmm;
684 int retval; 692 tsk->mm = NULL;
693 tsk->active_mm = NULL;
694
695 /*
696 * Are we cloning a kernel thread?
697 *
698 * We need to steal a active VM for that..
699 */
700 oldmm = current->mm;
701 if (!oldmm)
702 return 0;
703
704 if (clone_flags & CLONE_VM) {
705 atomic_inc(&oldmm->mm_users);
706 mm = oldmm;
707 goto good_mm;
708 }

无论我们在调用fork,vfork,clone的时候最终会调用do_fork函数,区别在于vfork和clone会给copy_mm传入一个CLONE_VM的flag,这个标识表示父子进程都运行在同样一个‘虚拟地址空间’上面(在Linux称之为lightweight process或者线程),当然也就共享同样的物理地址空间(Page Frames)。

copy_mm函数中,如果创建线程中有CLONE_VM标识,则表示父子进程共享地址空间和同一个内存描述符,并且只需要将mm_users值+1,也就是说mm_users表示正在引用该地址空间的thread数目,是一个thread level的counter。

mm_count呢?mm_count的理解有点复杂。

对Linux来说,用户进程和内核线程(kernel thread)都是task_struct的实例,唯一的区别是kernel thread是没有进程地址空间的,内核线程也没有mm描述符的,所以内核线程的tsk->mm域是空(NULL)。内核scheduler在进程context switching的时候,会根据tsk->mm判断即将调度的进程是用户进程还是内核线程。但是虽然thread thread不用访问用户进程地址空间,但是仍然需要page table来访问kernel自己的空间。但是幸运的是,对于任何用户进程来说,他们的内核空间都是100%相同的,所以内核可以’borrow'上一个被调用的用户进程的mm中的页表来访问内核地址,这个mm就记录在active_mm。

简而言之就是,对于kernel thread,tsk->mm == NULL表示自己内核线程的身份,而tsk->active_mm是借用上一个用户进程的mm,用mm的page table来访问内核空间。对于用户进程,tsk->mm == tsk->active_mm。

为了支持这个特别,mm_struct里面引入了另外一个counter,mm_count。刚才说过mm_users表示这个进程地址空间被多少线程共享或者引用,而mm_count则表示这个地址空间被内核线程引用的次数+1。

比如一个进程A有3个线程,那么这个A的mm_struct的mm_users值为3,但是mm_count为1,所以mm_count是process level的counter。维护2个counter有何用处呢?考虑这样的scenario,内核调度完A以后,切换到内核内核线程B,B ’borrow' A的mm描述符以访问内核空间,这时mm_count变成了2,同时另外一个cpu core调度了A并且进程A exit,这个时候mm_users变为了0,mm_count变为了1,但是内核不会因为mm_users==0而销毁这个mm_struct,内核只会当mm_count==0的时候才会释放mm_struct,因为这个时候既没有用户进程使用这个地址空间,也没有内核线程引用这个地址空间。

We'll try to explain the difference between the use of mm_users and mm_count with an example. Consider a memory descriptor shared by two lightweight processes. Normally, its mm_users field stores the value 2, while its mm_count field stores the value 1 (both owner processes count as one).

If the memory descriptor is temporarily lent to a kernel thread (see the next section), the kernel increases the mm_count field. In this way, even if both lightweight processes die and the mm_users field becomes zero, the memory descriptor is not released until the kernel thread finishes using it because the mm_count field remains greater than zero.

linux内核线程,进程,线程的更多相关文章

  1. 24小时学通Linux内核之进程

    都说这个主题不错,连我自己都觉得有点过大了,不过我想我还是得坚持下去,努力在有限的时间里学习到Linux内核的奥秘,也希望大家多指点,让我更有进步.今天讲的全是进程,这点在大二的时候就困惑了我,结果那 ...

  2. 深入Linux内核架构——进程管理和调度(上)

    如果系统只有一个处理器,那么给定时刻只有一个程序可以运行.在多处理器系统中,真正并行运行的进程数目取决于物理CPU的数目.内核和处理器建立了多任务的错觉,是通过以很短的间隔在系统运行的应用程序之间不停 ...

  3. (转)Linux内核之进程和系统调用

    Linux内核之进程和系统调用 什么是系统调用 在Linux的世界里,我们经常会遇到系统调用这一术语,所谓系统调用,就是内核提供的.功能十分强大的一系列的函数.这些系统调用是在内核中实现的,再通过一定 ...

  4. Linux内核之进程地址空间

    Linux内核之进程地址空间 内核中的函数以相当直接了当的方式获得动态内存: __get_free_pages 或 alloc_pages从分区页框分配器中获得页框; kmem_cache_alloc ...

  5. linux内核中创建线程方法

    1.头文件 #include <linux/sched.h> //wake_up_process() #include <linux/kthread.h> //kthread_ ...

  6. linux内核中创建线程方法【转】

    本文转载自:https://www.cnblogs.com/Ph-one/p/6077787.html 1.头文件 #include <linux/sched.h> //wake_up_p ...

  7. Linux内核分析--进程创建,执行,切换

    学号:351 原创作品转载请注明出处本实验来源 https://github.com/mengning/linuxkernel/ 实验要求 从整理上理解进程创建.可执行文件的加载和进程执行进程切换,重 ...

  8. Linux内核分析——进程的切换和系统的一般执行过程

    进程的切换和系统的一般执行过程 一.进程切换的关键代码switch_to分析 (一)进程调度与进程调度的时机分析 1.不同类型的进程有不同的调度需求 第一种分类: (1)I/O-bound:频繁进行I ...

  9. 深入理解Linux内核-进程

    1.进程的静态特性 进程:程序执行时的一个实例 进程描述符(task_struct): 进程的基本信息(thread_info).指向内存区描述符的指针(mm_struct).进程相关的tty(tty ...

  10. 20135239 益西拉姆 linux内核分析 进程的切换和系统的一般执行过程

    week 8 进程的切换和系统的一般执行过程 [ 20135239 原文请转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...

随机推荐

  1. mongo 3.0 备份和还原数据库 ,及too many positional arguments错误

    在mongo 3.0的操作 备份示例 ./mongodump -h localhost -d liongo -o ./ 错误方式: ./mongorestore -h 127.0.0.1 -d lio ...

  2. 日程管理app

    背景: 普通的笔记本显然具有保存占用较大空间的弊端.而笔记类app又借助于虚拟按键输入,便利度稍逊.假设使用电脑,又产生了较大空间的弊端. 手段: 成熟的书写识别技术 方法: 一.专有的划分有制定格子 ...

  3. cognos report同比环比以及默认为当前月分析

    现在的需求是按月份分析不同时期的余额数据,.(报表工具:cognos report:建模工具:FM) ------------------------------------------------- ...

  4. Swift学习笔记-1

    Apple官方开发手冊地址: https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/La ...

  5. Mongo读书笔记1 -- GridFS

      一个Mongo文档最大4M. GridFS不依赖于MongoDB, 其他符合规范的驱动都可以访问它. GridFS包含两部分:一部分存储文件名和其他metadata; 另一部分存储实际的文件,通常 ...

  6. [Backbone]8. Level 7: Router and history

    1. Ceate a route Class var AppRouter = Backbone.Router.extend({ }); 2. Add a route name it "sho ...

  7. Python标记去重

    预逻辑脚本代码: uniqueList = [] def isDuplicate(inValue): if inValue in uniqueList: return 1 else: uniqueLi ...

  8. MVC 之 <%%>相关内联代码块用法

    1.<%@ ... %> 添加引用; 2.<% ... %> <%%>之间可以执行服务端代码,如<% foreach (DataRow dataRow in ...

  9. vim配置 高亮+自动缩进+行号+折叠+优化

    一:修改 .vimrc即可 二: set nocompatible " 关闭 vi 兼容模式syntax on " 自动语法高亮colorscheme molokai " ...

  10. vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll【转】

     vlc的应用之三:动态调用vlc-0.9.4的libvlc.dll 2008-12-03 17:38:46 标签:WinForm C# libvlc.dll 休闲 vlc 原创作品,允许转载,转载时 ...