《深入理解计算机系统》家庭作业
* 8.9
答案:
进程对 |
是否并发 |
AB |
否 |
AC |
是 |
AD |
是 |
BC |
是 |
BD |
是 |
CD |
是 |
* 8.10
答案:
A. 调用一次,返回两次: fork
B. 调用一次,从不返回: execve, longjmp
C. 调用一次,返回一次或者多次: setjmp
* 8.11
答案:
这个程序会输出4个“hello”输出行。
因为Fork()函数的作用是调用一次返回两次。根据条件i<2,当 i = 0 时,输出2个hello,当 i = 1 时,输出2个hello。所以输出4个hello。
* 8.12
答案:
这个程序会输出8个“hello”输出行。
因为程序定义了一个doit()函数,里包含了两个Fork(),Fork()函数的作用是调用一次返回两次,所以返回4次,输出4个hello。main()函数中调用了doit()函数所以又输出4个hello
,一共输出8个hello。
** 8.23
答案:
一个可能的原因是,在第一个信号发给父进程之后,父进程进入handler,并且阻塞了SIGUSR2,第二个信号依然可以发送,然而,之后的3个信号便会被抛弃了。因为是连续发送,所以很可能是没等上下文切换,这5个信号就同时发送了。所以只有2个信号被接收。
** 9.14
答案:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
int fd;
char *start;
fd = open("hello.txt", O_RDWR, 0); //打开文件
start = mmap(NULL, 1, PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if(start == MAP_FAILED) return -1;//判断是否映射成功
(*start) = 'J';
munmap(start, 1);
return 0;
}
* 9.15
答案:
请求 |
块大小 |
块头部 |
malloc(3) |
8 |
0x9 |
malloc(11) |
16 |
0x11 |
malloc(20) |
24 |
0x19 |
malloc(21) |
32 |
0x21 |
* 9.19
答案:
1) a
a、对于伙伴系统,如果要申请大小为33的空间,那么需要分配64个空间。如果申请大小为65的空间,那么块大小就需要128,所以最多可能有约50%的空间被浪费。
b、最佳适配要搜索所有空间,所以肯定比首次适配要慢一些。
c、边界标记主要功能是释放一个块时,能立即和前后空闲块合并。如果空闲块不按顺序排列的话,其实也能够和前一个或者后一个空闲块进行合并,但如果要和前后一起合并,可能会有些困难,那需要搜索前后块在空闲链表中的位置,并且删除一个再进行合并。
d、其实任何分配器都可能有外部碎片,只要剩余的空闲块大小和足够但是单个都不够,就会产生外部碎片。
2) d
a、块大小递减,首次适配很容易找到,所以分配性能会很高。
b、最佳适配方法无论怎样,都要搜索所有的链表(除非维护成块大小递增的链表)。
c、是匹配的最小的。
d、块大小递增,那么最佳适配法找到的块和首次适配找到的块是同一个,因为最佳适配总是想找一个刚好大于请求块大小的空闲块。
3) c
保守的意思就是所有可能被引用的堆都会被标记,int像指针,所以可能认为它表示的地址是正在被引用的(实际上它只是个int)。
汇总
* 8.9
* 8.10
* 8.11
* 8.12
** 8.23
** 9.14
* 9.15
* 9.19
共计:十分