四次挥手状态
什么是系统调用
进程在系统上运行级别分为用户态和内核态,处于用户态的进程需要使用操作系统的功能,需要进行系统调用,切换成内核态调用操作系统的核心功能。
死锁的四个条件
互斥,持有并等待,非抢占,等待成环
解除死锁的四个方案
预防(资源分层),避免(银行家算法),检测(资源图),解除
内存管理机制
块式管理,分页管理,分段管理
分页管理和分段管理的区别
相同点:为了提高内存的利用率,较少碎片,页之间和段之间是不连续的,但是内部是连续的。
不同点:也的大小是固定的,由操作系统决定,但段的大小不固定。
Linux环境变量
用户级:~/.bashrc,~/.bashrc_profile
系统级:/etc/bashrc
、/etc/environment
、/etc/profile
、/etc/profile.d
环境生效的优先级:/etc/enviroment
–> /etc/profile
–> /etc/profile.d
–> ~/.bash_profile
–> /etc/bashrc
–> ~/.bashrc
一般用户级的环境在~/.bashrc_profile,系统环境变量一般在/etc/profile.d中设置。
Linux查看性能指标常用的命令
查看网络吞吐率,sar -n TCP 秒,表示每秒统计tcp连接数
为什么存在DMA?
DMA之间的IO流程:1,cpu向磁盘控制器发送消息表示要进行读数据。2,磁盘控制器准备好数据,向cpu发送中断请求。3,cpu会将磁盘控制器缓存中的数据一个字节一个字节传输到磁盘缓冲中。4,cpu再将磁盘缓冲中的数据拷贝到用户缓冲区中。5,在3,4阶段,cpu不能处理其他事情。
DMA流程:原理:IO设备和内存之间的数据传输不需要CPU参与。1,cpu向DMA发送消息,DMA向磁盘发送消息。2,磁盘控制器准备好数据,反馈给DMA控制器。3,DMA控制器将磁盘控制器缓冲区的数据传输到磁盘缓冲区。4,DMA通知CPU,cpu将数据从内核拷贝到用户缓冲区。
传统的文件传输的流程
文字描述:传统的文件传输要经过用户态和内核态之间的来回拷贝,消耗较大。从磁盘中读取数据并通过网卡发送出去为例:1,通过DMA将磁盘控制器的缓冲区中拷贝到内核态的缓冲区(磁盘缓冲区)。2,从内核态的缓冲区拷贝到用户态的缓冲区。3,将用户态的缓冲区拷贝到内核态缓冲区(Socket缓冲区)。4,通过DMA将数据拷贝到网卡。
如何实现零拷贝
如何提高文件传输的效率,较少拷贝的次数、减少内核态和用户态切换的次数。
1,mmap+write,mmap可以做到用户态缓冲区和内核态缓冲的数据的一个映射,可以避免了数据从内核态拷贝到用户态。流程:1,DMA将数据从磁盘控制器缓冲区拷贝的内核区。2,write操作直接将数据从磁盘缓冲区拷贝到socket缓冲区(内核态之间的数据拷贝)。3,通过DMA将数据从socket缓冲区发送到网卡。但是还是会有四次状态的切换,还会有内核态到用户态的变化。
2,sendfile:直接将磁盘缓冲区的数据通过CPU拷贝到socket缓冲区,不存在内核态和用户态之间的切换。
3,the-scatter-gather-DMA,直接可以认为数据从磁盘缓冲区通过DMA发送到网卡,sokcet缓冲会收到一些小字段的描述符。
磁盘缓冲区
磁盘缓冲区是位于内存中,存储着磁盘中部分数据,有缓存最近的数据和预读的功能。
(直接IO)大文件传输需要禁用磁盘缓冲区,避免浪费一次的DMA传输和抢占磁盘缓冲区的热点位置。
IO多路复用
select:调用select,会将slect监听的文件描述符集合从用户态拷贝到内核态,由内核态遍历判断是否有事件的发生,当有事件的发生,文件描述符集合从内核态拷贝到用户态,用户态在进行遍历找到触发的事件,slect有监听文件的上线为1024.
poll:和slect基本相同,但是监听的文件描述符的数量大于1024.
epoll:有三个方法,epoll-create创建一个文件描述fd,epoll-ect将文件描述fd加入到内核中的红黑树中,当有事件发生的fd,会通过回调函数调入到就绪链表中。epoll-wait函数会返回所有的就绪fd。epoll分为水平模式和边缘模式,边缘模式是指调用一个epoll-wait方法,其对应的就绪文件描述符不进行处理的话,下次调用就不会返回,水平模式的话,第一次调用不进行处理的话,下次调用的时候还可以继续处理。
常见的面试算法题
两个线程轮流打印1-100
public class Main {
static int i = 0;
public static void main(String[] args) {
Object o = new Object();
new Thread(()->{
while(i<100){
synchronized (o) {
if((i&1) ==0){
System.out.println(Thread.currentThread().getName()+":"+i);
o.notify();
i++;
}else {
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"偶数线程").start();
new Thread(()->{
while(i<100){
synchronized (o) {
if((i&1) ==1){
System.out.println(Thread.currentThread().getName()+":"+i);
o.notify();
i++;
}else {
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"奇数线程").start();
}
}
堆排序
import java.util.Arrays;
public class Main {
static int i = 0;
public static void main(String[] args) {
int []nums = new int[]{1,3,5,7,9,0,2,4,6,8,10};
heapSort(nums);
System.out.println(Arrays.toString(nums));
}
public static void heapSort(int []nums){
int len = nums.length;
initHeap(nums,len);
int index = len - 1;
for (int i =0;i<len;i++){
swap(nums,0,index);
heapfying(nums,0,index);
index --;
}
}
private static void initHeap(int[] nums, int len) {
for (int i = len / 2 - 1 ;i>=0;i--){
heapfying(nums,i,len);
}
}
private static void heapfying(int[] nums, int i, int len) {
int left = 2 * i + 1;
int right = 2 *i + 2;
int max_index = i;
if(left < len &&nums[left] > nums[max_index]){
max_index = left;
}
if(right < len &&nums[right] > nums[max_index]){
max_index = right;
}
if(i != max_index){
swap(nums,i,max_index);
heapfying(nums,max_index,len);
}
}
private static void swap(int[] nums, int i, int j) {
int tep = nums[i];
nums[i] = nums[j];
nums[j] = tep;
}
}
快排序
import java.util.Arrays;
public class Main {
static int i = 0;
public static void main(String[] args) {
int []nums = new int[]{1,3,5,7,9,0,2,4,6,8,10};
quickSort(nums,0,nums.length-1);
System.out.println(Arrays.toString(nums));
}
public static void quickSort(int []nums,int left , int right){
if(left>=right){
return;
}
int mid = partition(nums,left,right);
quickSort(nums,left,mid-1);
quickSort(nums,mid+1,right);
}
public static int partition(int []nums , int left , int right){
int flag = left ;
int index = left + 1;
for (int i=index;i<=right;i++){
if(nums[flag]>nums[i]){
swap(nums,index,i);
index ++;
}
}
swap(nums,index - 1,flag);
return index -1;
}
public static void swap(int[] nums, int i, int j) {
int tep = nums[i];
nums[i] = nums[j];
nums[j] = tep;
}
}
归并排序
import java.util.Arrays;
public class Main {
static int i = 0;
public static void main(String[] args) {
int[] nums = new int[]{1, 3, 5, 7, 9, 0, 2, 4, 6, 8, 10};
mergeSort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums));
}
public static void mergeSort(int[] nums, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
sort(nums, left, mid, right);
}
private static void sort(int[] nums, int left, int mid, int right) {
int i = left;
int j = mid + 1;
int index = 0;
int[] tep = new int[right - left + 1];
while (i <= mid && j <= right) {
if (nums[i] > nums[j]) {
tep[index++] = nums[j++];
} else {
tep[index++] = nums[i++];
}
}
while (i <= mid) {
tep[index++] = nums[i++];
}
while (j <= right) {
tep[index++] = nums[j++];
}
index = 0;
for (i = left; i <= right; i++) {
nums[i] = tep[index++];
}
}
public static void swap(int[] nums, int i, int j) {
int tep = nums[i];
nums[i] = nums[j];
nums[j] = tep;
}
}
leftBound
import java.util.Arrays;
public class Main {
static int i = 0;
public static void main(String[] args) {
int[] nums = new int[]{1, 4, 5, 7, 9, 0, 2, 4, 6, 8, 10};
Arrays.sort(nums);
System.out.println(leftBound(nums, 4));
}
public static int leftBound(int[] nums, int key) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (key == nums[mid]) {
right = mid - 1;
} else if (key > nums[mid]) {
left = mid + 1;
} else if (key < nums[mid]) {
right = mid - 1;
}
}
if (left >= nums.length || nums[left] != key) {
return -1;
}
return left;
}
}
rightBound
import java.util.Arrays;
public class Main {
static int i = 0;
public static void main(String[] args) {
int[] nums = new int[]{1, 4, 5, 7, 9, 0, 2, 4, 6, 8, 10};
Arrays.sort(nums);
System.out.println(rightBound(nums, 4));
}
public static int rightBound(int[] nums, int key) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (key == nums[mid]) {
left = mid + 1;
} else if (key > nums[mid]) {
left = mid + 1;
} else if (key < nums[mid]) {
right = mid - 1;
}
}
if (right <= 0 || nums[right] != key) {
return -1;
}
return right;
}
}
LRU
import java.util.HashMap;
class Node{
String key;
Object value;
Node pre,next;
}
class LRU {
HashMap<String,Node> map ;
Node head,tail;
int size;
int max ;
public LRU(int max){
this.max = max;
this.size = 0;
map = new HashMap<>();
head = new Node();
tail = new Node();
head.pre = null;
tail.next =null;
tail.pre = head;
head.next = tail;
}
public void add(String key , Object value){
if(map.containsKey(key)){
Node tep = map.get(key);
tep.value = value;
Node cpre = tep.pre;
Node cnext = tep.next;
cpre.next = cnext;
cnext.pre = cpre;
Node index = head.next;
tep.pre = head;
tep.next = index;
head.next = tep;
index.pre = tep;
}else {
Node tep = new Node();
tep.key = key;
tep.value = value;
map.put(key,tep);
Node index = head.next;
tep.pre = head;
tep.next = index;
head.next = tep;
index.pre = tep;
size ++;
if (size > max){
Node t = tail.pre.pre;
String tt = tail.pre.key;
t.next = tail;
tail.pre = t;
map.remove(tt);
}
}
}
public Object get(String key){
if(!map.containsKey(key)){
return null;
}
Node res = map.get(key);
Node cpre = res.pre;
Node cnext = res.next;
cpre.next = cnext;
cnext.pre = cpre;
Node index = head.next;
res.pre = head;
res.next = index;
head.next = res;
index.pre = res;
return res.value;
}
}
class Main{
public static void main(String[] args) {
LRU lru = new LRU(3);
lru.add("a","a");
lru.add("c","c");
lru.add("b","b");
lru.get("a");
lru.add("d","d");
Node cv = lru.head.next;
while (cv!=lru.tail){
System.out.println(cv.key+" "+cv.value);
cv = cv.next;
}
}
}