面试问题(非编程)汇总

1. 堆栈底层操作系统实现

   SS: 栈段寄存器,32位下是一个selector。 

   EBP:存储栈的底部。 ESP:指向栈的顶部。

   当函数调用时:一般是

#进入函数,现在esp指向栈顶,其值即 [CS 和 EIP ]

push        ebp        #在栈中存储ebp的值, SS[esp] 现在存储了

mov         ebp,esp  #将当前栈顶位置存储到ebp中.

sub         esp,0CCh #在栈中分配局部变量的空间,这里分配了16*c+c = 204 ?

# 现在可以进行各项操作...

# SS[ebp-8] 可以存储一个int 型变量, SS[ebp-12] 可以存储第二个int型变量. 

# 退出函数操作:

mov esp, ebp  # 恢复栈顶.

pop ebp         # 现在栈顶指向的是[CS 和 EIP]

ret                # 恢复CS, EIP


2. linux进程间通信方式

   信号、管道、socket、信号量(互斥)、消息队列、共享内存。

   消息队列:当进程发消息时,将用户空间的消息发送到内核空间,读消息时进行相反操作。与命名管道相比,消息队列的优势在于,它独立于发送和接收进程而存在,这消除了在同步命名管道的打开与关闭的可能产生的一些困难。

   管道:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。当写者太快或读者太慢时,写者会被阻塞。

   共享内存:共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。解决同步的问题的常用方法是通过使用信号量进行同步。与消息队列相比,它避免了不必要的复制。
3.
多态、动态绑定的实现原理

   c++多态是通过虚函数实现的。每个含有虚函数的类都包含了一个静态虚函数指针。

   多态也是通过动态绑定实现的,通过动态绑定,才能找到虚函数表指针。

   java多态是通过延迟绑定实现的,除private和static不是动态绑定其它都是动态绑定。
4.
磁盘的工作调度原理

   磁盘高速缓冲区:利于快速读写。

   CFQ(完全公平排队): 适用于桌面和多媒体应用。I/O请求优先级独立于进程优先级。

   NOOP(电梯式调度): 倾向于饿死读而利于写。适用于闪存设备。RAM、嵌入式系统。

   Deadline(截止时间调度): 以时间和硬盘区域进行分类。适用于数据库环境(oracle, mysql)。

   AS(预料I/O调度程序): 与Deadline一样,在读之后,要等6ms再进行读写。实际上这是把小写入流合并成大写入流。适用于写入文件较多的环境,如文件服务器。不适用于数据库。

5.  malloc 与 free:

     malloc: 分配空间是成块分配的. 

void free(void *ptr) {

	struct mem_control_block *free;

	free = ptr - sizeof(struct mem_control_block);

	free->is_available = 1;

	return;
}
      由上面可见, free( ptr )时,只需要将ptr 向后移动一个结构体大小(内存控制块),然后将其标记 is_isavailable 改为 1,即这一块是空闲的。

6. 正则式匹配:贪婪与非贪婪

    *(a) 与 *?(a)的区别:前者先匹配整个字符串,然后回溯[huí sù]到第一个a,作为匹配的字符串。后者先匹配到(a)然后将前一部分作为*匹配的内容。

7. linux 下线程与进程的区别:

    当线程不大于CPU时,不同的线程程运行于不同的CPU上。

    linux 系统线程数上限:1024。

8. 缓存穿透与雪蹦:

   穿透:缓存某一项对应的取值为null,每次查找该键对应的值时,都要查找数据库中取值。解决方案,设置上次查询时间(牺牲了一致性)。

   雪蹦:缓存不能命中(如到期),形成对数据的大量访问。解决方案,对快到期的cache,提前更新,更新cache时,加锁防止多个线程同时对一条数据进行查询。

9.内存屏障:

  对主存的一次访问一般花费硬件的数百次时钟周期。处理器通过缓存(caching)能够从数量级上降低内存延迟的成本这些缓存为了性能重新排列待定内存操 作的顺序。也就是说,程序的读写操作不一定会按照它要求处理器的顺序执行。当数据是不可变的,同时/或者数据限制在线程范围内,这些优化是无害的。CPU或者编译器的乱序是以保持显式的因果关系不变为前提的,但是它们都无法识别隐式的因果关系。有了内存屏障,就可以在隐式因果关系的场景中,保证因果关系逻辑正确。内存同步顺序永远不可能与时间顺序完全一致,毕竟CPU是并行工作的,而内存同步是串行的。

10.将内存虚拟成硬盘:

  可以把临时文件(热点文件)放在虚拟的硬盘上,提高系统的速度。内存读取速度:1333Mx2x64/8约10GBps。网卡10Gbps,但是,硬盘(即使ssd)却不过数百兆。

11.银行家算法与死锁:

银行家算法是避免死锁的,预防死锁是通过限制死锁的条件。  

互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
循环等待条件(Circular wait):系统中若干进程组成环路,改环路中每个进程都在等待相邻进程正占用的资源。
互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
循环等待条件(Circular wait):系统中若干进程组成环路,改环路中每个进程都在等待相邻进程正占用的资源。
1) 预防死锁。
这是一种较简单和直观的事先预防的方法。方法是通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或者几个,来预防发生死锁。预防死锁是一种较易实现的方法,已被广泛使用。但是由于所施加的限制条件往往太严格,可能会导致系统资源利用率和系统吞吐量降低。
2) 避免死锁。
该方法同样是属于事先预防的策略,但它并不须事先采取各种限制措施去破坏产生死锁的的四个必要条件,而是在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免发生死锁。
3)检测死锁。
这种方法并不须事先采取任何限制性措施,也不必检查系统是否已经进入不安全区,此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源,然后采取适当措施,从系统中将已发生的死锁清除掉。
检测方法包括定时检测、效率低时检测、进程等待时检测等。
4)解除死锁。
这是与检测死锁相配套的一种措施。当检测到系统中已发生死锁时,须将进程从死锁状态中解脱出来。常用的实施方法是撤销或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,以继续运行。死锁的检测和解除措施,有可能使系统获得较好的资源利用率和吞吐量,但在实现上难度也最大。
银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系

银行家算法:

统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。

12.寻找数组中逆序数据对、寻找值为1-N数组中重复数:

   寻找逆序对:1)可采用冒泡法,每次交换必是一个逆序对。2)采用归并排序法,A、B分别有序时,若A的最大值小于B的最小值,则不会产生逆序对,否则会产生逆序对。

13. JDBC相关:

   preparedstatement, statement, callablestatement:前者只是预编译SQL语句并可以设置占位符、statement用于执行静态语句和得到结果、callablestatement可以调用存储过程。

14. 







   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章