2025年linux软件工程师笔试题及答案_第1页
2025年linux软件工程师笔试题及答案_第2页
2025年linux软件工程师笔试题及答案_第3页
2025年linux软件工程师笔试题及答案_第4页
2025年linux软件工程师笔试题及答案_第5页
已阅读5页,还剩15页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2025年linux软件工程师笔试题及答案一、基础题(每题5分,共40分)1.简述Linux文件系统中inode的作用,并说明如何查看一个文件的inode编号。答案:inode是Linux文件系统中存储文件元数据的结构,包含文件大小、权限、创建/修改时间、数据块指针等信息(文件名存储在目录的块中,不占用inode)。每个文件/目录对应唯一inode号。查看inode编号可使用`ls-i`命令(如`ls-i/etc/passwd`),或`stat`命令查看输出中的"Inode"字段。2.当执行`rmfile.txt`时,文件数据是否立即被操作系统擦除?说明原因。答案:不会立即擦除。rm命令仅删除文件的目录项(即断开文件名与inode的链接),并减少inode的链接计数。当链接计数降为0且无进程打开该文件(即文件描述符引用计数为0)时,文件占用的数据块才会被标记为可重用。数据本身会在后续写入新数据时被覆盖。3.写出`psaux`输出中"VSZ"和"RSS"字段的含义,并说明二者的区别。答案:VSZ(VirtualMemorySize)是进程虚拟内存总大小,包括进程可访问的所有内存区域(代码段、数据段、共享库、未分配但保留的空间等);RSS(ResidentSetSize)是进程当前驻留物理内存的大小(实际占用的RAM)。VSZ可能远大于RSS,因为虚拟内存中很多区域未被实际加载到物理内存(如未使用的共享库页面)。4.编写一个shell脚本,统计当前系统中所有状态为"ESTABLISHED"的TCP连接数量(要求使用netstat或ss命令)。答案:```bash!/bin/bash使用ss命令更高效(替代netstat)ss-tstateestablished|awk'NR>1{count++}END{printcount}'或使用netstatnetstat-ant|grepESTABLISHED|wc-l```(注:ss命令比netstat更高效,因为它直接读取内核网络栈数据结构)5.说明硬链接(hardlink)和符号链接(symboliclink)的区别,以及创建它们的命令。答案:硬链接通过增加inode的链接计数实现,与原文件共享同一inode,无法跨文件系统创建,删除原文件不影响硬链接(只要链接计数>0);符号链接是独立文件,存储原文件路径,可跨文件系统,原文件删除后符号链接变为“断链”。创建硬链接用`ln源文件硬链接名`,符号链接用`ln-s源文件符号链接名`。6.简述Linux内核中进程(process)和线程(thread)的区别,以及内核如何调度它们。答案:进程是资源分配的基本单位(拥有独立的地址空间、文件描述符表等),线程是调度执行的基本单位(共享进程的资源,仅拥有独立的寄存器、栈、线程ID等)。Linux内核通过轻量级进程(LWP)实现线程,每个线程在内核中表现为独立的task_struct结构,调度时与普通进程使用相同的调度算法(如CFS),但共享父进程的资源。7.当使用`tar-czvfarchive.tar.gzdir/`打包目录时,`-z`和`-v`参数的作用分别是什么?若要排除目录中所有扩展名为.swap的文件,应如何修改命令?答案:`-z`表示使用gzip压缩算法;`-v`表示显示详细输出(列出处理的文件)。排除.swap文件可使用`--exclude='.swap'`参数,完整命令:`tar-czvfarchive.tar.gz--exclude='.swap'dir/`。8.简述Linux系统中用户空间与内核空间的隔离机制,以及用户程序如何调用内核功能。答案:通过CPU的特权级(x86的ring0/ring3)实现隔离,内核运行在ring0(特权模式),用户程序运行在ring3(用户模式),用户空间无法直接访问内核内存或硬件。用户程序通过系统调用(如`open()`、`read()`)陷入内核,触发软中断(如x86的int0x80或syscall指令),切换到内核态执行对应内核函数,完成后返回用户态。二、进阶题(每题8分,共40分)1.简述Linux内核模块(kernelmodule)的加载过程,并说明如何查看已加载模块的依赖关系。答案:加载过程:①用户使用`insmod`或`modprobe`命令将模块二进制文件(.ko)加载到内核;②内核检查模块的合法性(如MagicNumber、符号表);③执行模块初始化函数(`module_init()`注册的函数),可能申请内存、注册设备驱动、创建文件系统节点等;④更新内核模块链表,记录模块信息(如引用计数)。查看依赖关系可使用`modinfo模块名`(显示depends字段)或`lsmod`(列出所有模块及其引用计数),`modprobe-d模块名`也可查看依赖树。2.解释虚拟内存(VirtualMemory)到物理内存(PhysicalMemory)的映射机制,涉及哪些关键数据结构和硬件支持?答案:虚拟内存通过页表(PageTable)映射到物理内存。x86-64系统使用四级页表(PML4、PDPT、PD、PT),每个页表项(PTE)存储物理页框号(PFN)及访问权限、脏位等标志。硬件支持包括MMU(内存管理单元)负责地址转换,TLB(转换后援缓冲器)缓存最近使用的页表项以加速转换。当虚拟页未映射到物理内存(缺页中断)时,内核从磁盘(交换分区或文件)加载对应页到物理内存,并更新页表。3.简述CFS(CompletelyFairScheduler)调度器的核心思想,说明其如何实现“公平”调度。答案:CFS基于“虚拟运行时间”(vruntime)实现公平调度。每个进程的vruntime根据实际运行时间和权重(nice值转换而来)计算(vruntime=实际运行时间(NICE_0_LOAD/进程权重))。CFS维护一个红黑树(rbtree),按vruntime排序,每次选择vruntime最小的进程运行,确保所有进程的vruntime尽可能接近,避免进程长时间等待。对于实时进程(优先级高于0),CFS会让位于实时调度类(如FIFO/RR)。4.说明epoll的LT(LevelTriggered)和ET(EdgeTriggered)模式的区别,并举例说明ET模式的使用注意事项。答案:LT模式(水平触发):当文件描述符就绪(如可读)时,epoll会重复通知(只要数据未被完全读取);ET模式(边缘触发):仅在状态变化时通知一次(如从不可读到可读的瞬间)。ET模式要求用户必须一次性读取所有可用数据(如循环调用`read()`直到返回EAGAIN),否则可能丢失事件。例如,使用ET模式监听socket可读事件时,需在`read()`返回-1且`errno==EAGAIN`时停止读取,否则剩余数据不会再次触发通知,导致数据积压。5.简述Linux内核中内存泄漏(MemoryLeak)的常见场景及调试方法。答案:常见场景:①内核模块中申请内存(如`kmalloc()`、`vmalloc()`)后未释放;②分配的内核对象(如`structtask_struct`)未正确释放引用计数;③设备驱动中DMA缓冲区未正确释放。调试方法:①使用`kmemleak`工具(需内核配置`CONFIG_DEBUG_KMEMLEAK`),通过`echoscan>/sys/kernel/debug/kmemleak`触发扫描,输出泄漏的内存地址和调用栈;②`slabtop`查看slab缓存使用情况,定位异常增长的缓存;③内核调试符号(`CONFIG_DEBUG_INFO`)配合`gdb`分析内核转储(kdump);④自定义钩子函数(如覆盖`kmalloc`/`kfree`)记录分配/释放操作。三、编程题(每题10分,共30分)1.编写C程序,使用多线程实现文件拷贝功能,要求支持指定线程数(通过命令行参数传入)和分块大小(如每线程处理1MB数据)。需处理文件大小不能被分块数整除的情况。答案:```cinclude<stdio.h>include<stdlib.h>include<pthread.h>include<fcntl.h>include<unistd.h>include<sys/stat.h>typedefstruct{intsrc_fd,dest_fd;off_tstart;off_tend;size_tblock_size;}ThreadArgs;voidcopy_thread(voidarg){ThreadArgsargs=(ThreadArgs)arg;charbuffer=malloc(args->block_size);if(!buffer){perror("malloc");pthread_exit(NULL);}lseek(args->src_fd,args->start,SEEK_SET);lseek(args->dest_fd,args->start,SEEK_SET);off_tcurrent=args->start;while(current<args->end){size_tread_size=(args->end-current)<args->block_size?(args->end-current):args->block_size;ssize_tbytes_read=read(args->src_fd,buffer,read_size);if(bytes_read<=0)break;write(args->dest_fd,buffer,bytes_read);current+=bytes_read;}free(buffer);returnNULL;}intmain(intargc,charargv[]){if(argc!=5){fprintf(stderr,"Usage:%s<src><dest><thread_num><block_size(MB)>\n",argv[0]);return1;}intsrc_fd=open(argv[1],O_RDONLY);intdest_fd=open(argv[2],O_WRWR|O_CREAT|O_TRUNC,0644);if(src_fd<0||dest_fd<0){perror("open");return1;}structstatst;fstat(src_fd,&st);off_tfile_size=st.st_size;intthread_num=atoi(argv[3]);size_tblock_size=atoi(argv[4])10241024;//MB转字节pthread_tthreads=malloc(thread_numsizeof(pthread_t));ThreadArgsargs=malloc(thread_numsizeof(ThreadArgs));off_tchunk_size=file_size/thread_num;for(inti=0;i<thread_num;i++){args[i].src_fd=src_fd;args[i].dest_fd=dest_fd;args[i].start=ichunk_size;args[i].end=(i==thread_num-1)?file_size:(i+1)chunk_size;args[i].block_size=block_size;pthread_create(&threads[i],NULL,copy_thread,&args[i]);}for(inti=0;i<thread_num;i++){pthread_join(threads[i],NULL);}close(src_fd);close(dest_fd);free(threads);free(args);return0;}```关键点:通过`lseek`定位各线程的读写位置,使用`pthread_create`创建线程,每个线程处理独立的文件区间,最后`pthread_join`等待所有线程完成。处理剩余数据通过最后一个线程覆盖`file_size`解决。2.编写信号处理程序,当进程收到SIGINT信号(Ctrl+C)时,先输出"CaughtSIGINT,cleaningup...",然后执行自定义清理函数(如释放动态分配的内存),最后正常退出。要求信号处理函数中不直接调用非异步安全函数。答案:```cinclude<stdio.h>include<stdlib.h>include<signal.h>include<unistd.h>volatilesig_atomic_tsigint_received=0;voiddynamic_data=NULL;voidcleanup(){if(dynamic_data){free(dynamic_data);dynamic_data=NULL;printf("Cleanedupdynamicdata\n");}}voidsigint_handler(intsig){sigint_received=1;//仅设置标志,异步安全}intmain(){dynamic_data=malloc(1024);//模拟动态分配if(!dynamic_data){perror("malloc");return1;}structsigactionsa;sa.sa_handler=sigint_handler;sigemptyset(&sa.sa_mask);sa.sa_flags=0;sigaction(SIGINT,&sa,NULL);while(!sigint_received){printf("Running...\n");sleep(1);}printf("CaughtSIGINT,cleaningup...\n");cleanup();//在主循环中调用清理函数(非信号处理函数内)return0;}```关键点:信号处理函数仅设置原子标志(`sig_atomic_t`保证操作原子性),主循环检测到标志后调用清理函数,避免在信号处理函数中调用`printf`、`free`等非异步安全函数(可能导致竞态条件或崩溃)。3.编写C程序,使用共享内存(shm)实现两个进程间的通信:进程A向共享内存写入字符串"HellofromA",进程B读取该字符串并输出。要求处理共享内存的创建、连接、分离和删除。答案:```c//进程A(写入端)include<stdio.h>include<stdlib.h>include<string.h>include<sys/ipc.h>include<sys/shm.h>defineSHM_KEY0x1234defineSHM_SIZE1024intmain(){intshmid=shmget(SHM_KEY,SHM_SIZE,IPC_CREAT|0666);if(shmid<0){perror("shmget");return1;}charshm_addr=shmat(shmid,NULL,0);if(shm_addr==(char)-1){perror("shmat");return1;}strcpy(shm_addr,"HellofromA");printf("Wrotetosharedmemory:%s\n",shm_addr);shmdt(shm_addr);//分离共享内存//不立即删除,等待进程B读取return0;}//进程B(读取端)include<stdio.h>include<stdlib.h>include<sys/ipc.h>include<sys/shm.h>defineSHM_KEY0x1234defineSHM_SIZE1024intmain(){intshmid=shmget(SHM_KEY,SHM_SIZE,0666);if(shmid<0){perror("shmget");return1;}charshm_addr=shmat(shmid,NULL,0);if(shm_addr==(char)-1){perror("shmat");return1;}printf("Readfromsharedmemory:%s\n",shm_addr);shmdt(shm_addr);//分离shmctl(shmid,IPC_RMID,NULL);//标记为删除(所有进程分离后释放)return0;}```关键点:进程A使用`IPC_CREAT`创建共享内存,进程B通过相同key获取;`shmat`连接内存,`shmdt`分离;`shmctl(IPC_RMID)`标记共享内存为待删除(实际删除发生在最后一个进程分离后)。四、综合题(20分)假设某Linux服务器出现CPU使用率持续90%以上的问题,请设计排查流程,并说明可能的原因及对应的解决方法。答案:排查流程:1.确认负载来源:使用`top`或`htop`查看CPU占用最高的进程(关注%CPU列),记录进程PID。2.分析进程行为:-若为用户进程(如应用程序),使用`strace-pPID`

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论