大家好,又见面了,我是你们的朋友全栈君。
从用户态到内核态切换可以通过三种方式,或者说会导致从用户态切换到内核态的操作:
当发生用户态到内核态的切换时,会发生如下过程(本质上是从“用户程序”切换到“内核程序”)
而之后从内核态返回用户态时,又会进行类似的工作。
用户态和内核态之间的切换有一定的开销,如果频繁发生切换势必会带来很大的开销,所以要想尽一切办法来减少切换。这也是面试常考的问题。
3.1 减少线程切换
因为线程的切换会导致用户态和内核态之间的切换,所以减少线程切换也会减少用户态和内核态之间的切换。那么如何减少线程切换呢?
3.2 一个面试问题
I/O 频繁发生内核态和用户态切换,怎么解决。
首先要同意这个说法,即I/O会导致系统调用,从而导致内核态和用户态之间的切换。因为对I/O设备的操作是发生在内核态。那如何减少因为I/O导致的系统调用呢?答案是:使用户进程缓冲区。下面解释一下原因
用户进程缓冲区
你看一些程序在读取文件时,会先申请一块内存数组,称为buffer,然后每次调用read,读取设定字节长度的数据,写入buffer。之后的程序都是从buffer中获取数据,当buffer使用完后,在进行下一次调用,填充buffer。所以说:用户缓冲区的目的就是是为了减少系统调用次数,从而降低操作系统在用户态与核心态切换所耗费的时间。除了在进程中设计缓冲区,内核也有自己的缓冲区。
内核缓存区
当一个用户进程要从磁盘读取数据时,内核一般不直接读磁盘,而是将内核缓冲区中的数据复制到进程缓冲区中。但若是内核缓冲区中没有数据,内核会把对数据块的请求,加入到请求队列,然后把进程挂起,为其它进程提供服务。等到数据已经读取到内核缓冲区时,把内核缓冲区中的数据读取到用户进程中,才会通知进程,当然不同的IO模型,在调度和使用内核缓冲区的方式上有所不同。
小结
图中的read,write和sync都是系统调用。read是把数据从内核缓冲区复制到进程缓冲区。write是把进程缓冲区复制到内核缓冲区。当然,write并不一定导致内核的缓存同步动作sync,比如OS可能会把内核缓冲区的数据积累到一定量后,再一次性同步到磁盘中。这也就是为什么断电有时会导致数据丢失。所以说内核缓冲区,可以在OS级别,提高磁盘IO效率,优化磁盘写操作。
为什么加锁和释放锁会导致上下文切换
Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。但是由于使用Mutex Lock需要将当前线程挂起并从用户态切换到内核态来执行,这种切换的代价是非常昂贵的因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/192121.html原文链接:https://javaforall.cn