1. linux内核内存分配方式
Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间
2. new/delete和malloc/free的区别
(1)操作对象有所不同。
malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。对于非内部数据类的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free。
(2)在用法上也有所不同。函数malloc的原型如下:void * malloc(size_t size);
用malloc申请一块长度为length的整数类型的内存,程序如下:int *p = (int *) malloc(sizeof(int) * length);
malloc返回值的类型是void *,所以在调用malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。
malloc 函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
函数free 的原型如下:
void free( void * memblock );
为什么free 函数不象malloc 函数那样复杂呢?这是因为指针p 的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。如果p 是NULL 指针,那么free
对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。
new/delete 的使用要点
运算符new 使用起来要比函数malloc 简单得多
3. 驱动中断
在Linux设备驱动编程中的中断服务程序执行并不存在进程的上下文,因此在请求中断服务程序的时间尽可能的短,因此,Linux在中断处理中引入了顶半部和底半部分离的机制。
所谓的中断就是指CPU在执行程序的过程中,出现了某些突发事件待急处理,CPU必须暂停当前运行的程序,转去处理突发事件,处理完毕后CPU又会返回原程序被中断打断的位置并继续执行。根据中断源,中断可以分为内部中断和外部中断,内部中断的中断源来自CPU内部(软中断指令,溢出,除法错误等),外部中断来自CPU处理器的外部,由于在arm处理器中可以有硬件可控制中断,所以提供了外部中断请求。
在Linux内核中为了处理中断的时间竟可能短和中断处理完成大量工作之间找到一个平衡点,Linux将中断处理分为顶半部和底半部,在顶半部完成尽可能少的紧急功能,它往往只是简单的读取寄存器中中断状态并清除中断标志后就进行登记中断的工作,登记中断的意味将底半部处理程序挂到设备的底半部执行队列中去,这样顶半部可以尽可能快的服务更多的中断请求,而底半部则要处理完中断的所有事情。
在Linux内核中对于中断的请求和释放都要使用到内核的request_irq()和free_irq()函数,而在底半部机制中主要有tasklet,工作队列和软中断
4. 紧凑模式和非紧凑性模式
Struct
{
Char d;
char b;
int a;
double c;
}A;
Struct
{
Char d;
int a;
char b;
double c;
}B;
紧凑模式:sizeof(A) =1+1+2+4+8=16
非紧凑模式:sizeof(B) =4+4+4+8=20
5. 堆和栈的区别
1)程序的内存分配:
栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等
堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收
2)申请方式:
stack: 由系统自动配
heap: 需要程序员自己申请,并指明大小
3)申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
4)申请后的系统响应及大小限制:
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢
出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表
中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的
首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。
另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部
分重新放入空闲链表中。
5)堆栈的存储内容 :
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可
执行语句)的地址,然后是函数的各个参数,参数是由右往左入栈
的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地
址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
6. 调用函数时的压栈顺序
在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可
执行语句)的地址,然后是函数的各个参数,参数是由右往左入栈
的,然后是函数中的局部变量。注意静态变量是不入栈的。
7. 局部变量和全局变量
1)全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包括全局变量定义的源文件需要用extern关键字再次声明这个全局变量
2)局部变量只有局部作用域,它是自动对象,他在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用结束后,变量就被撤销,其所占用的内存也被收回。
8. bootloader启动过程
第一步:当系统在上电或者复位的后,CPU的PC指针会指向物理地址的0x00000000处,这里的物理地址表示片内的IROM存储器,它固化了系统启动的BL0引导代码,这段代码会选择以什么方式启动,就会找到bootloader的BL1存放的地址,由于BL1不支持片上执行,所以会把IROM这段代码拷贝到IRAM中去,但是在拷贝之前,IROM会先把IRAM的起始4个地址分别写上一定的内容(不过通常只写0x00地址为BL1所占空间的大小(一般是8k),而其他三个地址全写为0),把BL1这段代码拷贝到IRAM后,IROM的使命就快要完成了,IROM的最后一个任务就是把PC指针指向放BL1的那块地址的起始位置,然后就按照这个地址的指令开始执行。
第二步:这个时候开始执行BL1的代码。这段代码的功能是初始化硬件,比如串口,内存,显示器,按键等,还有电源、时钟初始化,堆栈空间,以及各种必要的初始化,并且会提供一个命令行,可以进行交互。在这之后会有一个设置内核参数的过程,这些参数在内存中的存在方式也是以结构体存储,以链表进行关联的,而这个 链表有一个固定的起始地址0x30000100;每一个结构体代表一个信息,并首尾相连,内核在需要这些参数时,就可以再对应的地址上取数据。
第三部:第二步执行完毕后,就要把kernel的代码拷贝到SDRAM中的一个指定地址,在Linux中一般拷贝到物理地址的0x20008000处,并且会把这个地址强制转换成一个函数指针,并且向这个函数中传递一些参数,最终会到内核中执行内核代码。这个时候,内核就会被引导到执行状态。
9. 宏定义、内联函数、和普通函数的区别
1)内联函数的执行过程与带参数宏定义很相似,但参数的处理不同。带参数的宏定义并不对参数进行运算,而是直接替换;内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数。
2)内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定;而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患
3)宏做的是简单的字符串替换(只是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.
宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.
宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.
宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.
10. 进程间通讯方式
传统的进程间通信方式:无名管道,有名管道和信号
SYS V IPC对象:共享内存,消息队列和信号灯
BSD通信方式:套接字
11. Input子系统
输入子系统由驱动层(Drivers),输入子系统核心层( Input Core )和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下等都是通过 Driver -> InputCore -> Eventhandler -> userspace 的顺序到达用户空间传给应用程序。下面介绍各部分的功能:
(1)驱动层功能:负责和底层的硬件设备打交道,将底层硬件设备对用户输入的响应转换为标准的输入事件以后再向上发送给输入子系统核心层(Input Core)。
(2)Input系统核心层:Input Core即Input Layer,由driver/input/input.c及相关头文件实现,它对下提供了设备驱动层的接口,对上提供了事件处理层(Event Handler)的编程接口。
(3)事件处理层将硬件设备上报的事件分发到用户空间和内核。