diff --git a/README.md b/README.md index 364e399..4beca2f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# 《后端技术总结》 + +# 《大厂面试指北》 最佳阅读地址:http://notfound9.github.io/interviewGuide/ @@ -6,17 +7,14 @@ Github项目主页:https://github.com/NotFound9/interviewGuide 作者博客地址:https://juejin.im/user/5b370a42e51d4558ce5eb969 - ## 为什么要做这个开源项目? 之前在业余时间阅读技术书籍时,发现只阅读而不产出,这样收效甚微。所以就在网上找了很多常见的技术问题,根据自己的技术积累,查阅书籍,阅读文档和博客等资料,尝试着用自己的话去写了很多原创解答,最终整理开源到Github。一方面是便于自己复习巩固,一方面是将这些自己写的解答开源出来分享给大家,希望可以帮助到大家,也欢迎大家一起来完善这个项目,为开源做贡献。 -欢迎大家进群一起学习进步! -
- + ## 目录 - [首页](README.md) diff --git a/docs/ArrayList.md b/docs/ArrayList.md index 3b8cf8d..d2717bb 100644 --- a/docs/ArrayList.md +++ b/docs/ArrayList.md @@ -17,7 +17,7 @@ #### 1.底层使用的数据结构 -* Arraylist 底层使用的是**Object数组**,初始化时就会指向的会是一个static修饰的空数组,数组长度一开始为**0**,插入第一个元素时数组长度会初始化为**10**,之后每次数组空间不够进行扩容时都是增加为原来的**1.5倍**。ArrayList的空间浪费主要体现在在list列表的结尾会预留一定的容量空间(为了避免添加元素时,数组空间不够频繁申请内存),而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放后继指针next和前驱指针pre以及数据) +* ArrayList 底层使用的是**Object数组**,初始化时就会指向的会是一个static修饰的空数组,数组长度一开始为**0**,插入第一个元素时数组长度会初始化为**10**,之后每次数组空间不够进行扩容时都是增加为原来的**1.5倍**。ArrayList的空间浪费主要体现在在list列表的结尾会预留一定的容量空间(为了避免添加元素时,数组空间不够频繁申请内存),而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放后继指针next和前驱指针pre以及数据) * LinkedList 底层使用的数据结构是**双向链表**,每个节点保存了指向前驱节点和后继结点的指针。初始化时,不执行任何操作,添加第一个元素时,再去构造链表中的节点。 diff --git a/docs/Git.md b/docs/Git.md new file mode 100644 index 0000000..83ed882 --- /dev/null +++ b/docs/Git.md @@ -0,0 +1,126 @@ +##### git命令使用 + +`git branch dev` 创建一个名称为dev的分支 + +`git checkout dev`切换到dev分支上 + + +`git checkout -b dev ` 从当前分支上创建出一个新分支dev + + +`git merge dev` 假设当前为master分支,执行这条命令后会将dev分支合并到当前master分支,合并完成后,master分支和dev分支会变成同一个分支 + +`git:(dev) git rebase master` 假设当前为dev分支,git rebase master命令会将当dev的更改进行回退,回退到与main分支交汇的地方,将这些更改暂存到rebase目录,然后将master上面的提交拿过来,让dev分支更新到master分支那样,然后再把之前暂存的更改应用上,中间如果出现冲突,需要解决冲突,解决完冲突后,使用git add 将更新添加上,然后使用git rebase --continue继续合并。如果中间需要中断合并那么可以使用git rebase —abort。 + +在rebase完成后,我们dev分支已经是最新了,但是master上还是老的代码,我们需要使用git checkout master 切换到master分支上,然后使用git rebase dev将dev上面的更改移动到master上来,然后push到远程。 +![image-20210603172535748](../static/image-20210603172535748.png) + +`git checkout HEAD^` 将当前head指向上1次提交 + +`git checkout HEAD~3` 将当前head指向上3次提交 + +`git reset HEAD~1` 回滚到上一次提交 + +`git reset HEAD` 生成一个新的提交,用于将上一个提交的更改撤销掉,等价于`git reset HEAD~1` + +`git cherry-pick C3 C4 C7`将其他分支上的C3提交,C4提交,C7提交拿到这个分支上面来 + +`git rebase -i HEAD~3` 合并最近的两次提交为一次提交记录,执行这个命令后会进入vim界面,然后会出现3次提交的记录 + +```java +pick 115e825 queryCreditsMonth +pick 4cedfe6 queryCreditsMonth +pick b3dccfd nickname +``` + +有一下操作符: +pick:保留该commit(缩写:p) +reword:保留该commit,但我需要修改该commit的注释(缩写:r) +edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e) +squash:将该commit和前一个commit合并(缩写:s) +fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f) +exec:执行shell命令(缩写:x) +drop:我要丢弃该commit(缩写:d) + +咱们如果要把三次提交合并成一个就改成这样 + +``` +pick 115e825 queryCreditsMonth +s 4cedfe6 queryCreditsMonth +s b3dccfd nickname +``` + +然后保存退出,然后会进入填写commit说明的地方,我们直接保存就好了,这样就完成了,会生成一个新的commit + +```java +commit b3dccfd2c2173fa0a6358de604b6541c8c6c644a (HEAD -> feature-dev) +Date: Fri May 7 16:29:22 2021 +0800 + + nickname + + nickname + + change credits +``` + + + +`git commit -amend`可以修改最后一次提交的commit说明 + + + + + + + +##### rebase出现了冲突怎么办? + +假设master上跟我们改了同一行,其实就会造成冲突 +例如下面这个就是我们需要解决的冲突,<<<<< HEAD 到====== 之间为其他分支上别人的更改,======到>>>>>>> change credits之间为我们自己在dev分支上的更改,我们需要解决冲突,然后使用git add对文件进行提交 +```java + @Override + public List creditsMonthsQuery(Integer months, long year) { +<<<<<<< HEAD + List creditsMonth = creditsMonthsMapper.creditsMonthsQuery(months, year); + for(CreditsMonthsUser creditsMonthsUser : creditsMonth){ + String nickname = WechatUtil.decodeNickName(creditsMonthsUser.getNickname()); + creditsMonthsUser.setNickname(nickname); + } + return creditsMonth; +======= + Integer a = 100; + return creditsMonthsMapper.creditsMonthsQuery(months, year); +>>>>>>> change credits + } + +``` + +##### 日常开发流程应该是怎么样的呢? +1. git fetch origin dev 拉取远程的dev分支到本地,本地也会创建出dev分支 + +2.git checkout -b feature-dev 我们自己从dev分支创建出一个feature-dev分支,用于我们自己开发 + +3.我们自己在feature-dev开发了一些功能后,进行提交时,可能其他人往dev分支上提交了更新,我们需要将更新拿到本地 + +4. + +git checkout dev 切到dev分支 +git pull origin dev 将其他人在远程dev上的提交拉到本地 + +5. + +git checkout feature-dev + +git rebase dev 将dev上的更改应用到我们的feature-dev分支 + +然后可能会出现冲突,我们对冲突进行合并, + +然后对修改后的文件使用git add +文件名 进行添加, + +添加完成后使用git rebase --continue就可以继续,然后合并完成(如果需要中断rebase操作可以使用git rebase --abort) + +6.git checkout feature-dev + +git rebase feature-dev 就可以把feature-dev上合并好的更改拿到dev分支上 + +7. git push origin dev 就可以将dev分支上的更改提交到远程 \ No newline at end of file diff --git a/docs/JavaJVM.md b/docs/JavaJVM.md index aa8edeb..fbf2eec 100644 --- a/docs/JavaJVM.md +++ b/docs/JavaJVM.md @@ -42,9 +42,9 @@ 堆存储了几乎所有对象实例和数组,是被所有线程进行共享的区域。在逻辑上是连续的,在物理上可以是不连续的内存空间(在存储一些类似于数组的这种大对象时,基于简单和性能考虑会使用连续的内存空间)。 #### 方法区 -存储了被虚拟机加载的类型信息,常量,静态变量等数据,在JDK8以后,存储在元空间中(以前是存储在堆中的永久代中,JDK8以后已经没有永久代了)。 +存储了被虚拟机加载的**类型信息**,**常量**,**静态变量**等数据,在JDK8以后,存储在**方法区的元空间**中(以前是存储在堆中的永久代中,JDK8以后已经没有永久代了)。 -运行时常量池是方法区的一部分,会存储各种字面量和符号引用。具备动态性,运行时也可以添加新的常量入池(例如调用String的intern()方法时,如果常量池没有相应的字符串,会将它添加到常量池)。 +**运行时常量池**是方法区的一部分,会存储各种字面量和符号引用。具备动态性,运行时也可以添加新的常量入池(例如调用String的intern()方法时,如果常量池没有相应的字符串,会将它添加到常量池)。 ### 直接内存区(不属于虚拟机运行时数据区) @@ -588,13 +588,15 @@ Minor GC:对新生代进行回收,不会影响到年老代。因为新生代 Full GC:也叫 Major GC,对整个堆进行回收,包括新生代和老年代。由于Full GC需要对整个堆进行回收,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数,导致Full GC的原因包括:老年代被写满和System.gc()被显式调用等。 ### 触发Minor GC的条件有哪些? + 1.为新对象分配内存时,新生代的Eden区空间不足。 新生代回收日志: -``` +```java 2020-05-12T16:15:10.736+0800: 7.803: [GC (Allocation Failure) 2020-05-12T16:15:10.736+0800: 7.803: [ParNew: 838912K->22016K(943744K), 0.0982676 secs] 838912K->22016K(1992320K), 0.0983280 secs] [Times: user=0.19 sys=0.01, real=0.10 secs] ``` ### 触发Full GC的条件有哪些? + 主要分为三种: #### 1.system.gc() diff --git a/docs/JavaMultiThread.md b/docs/JavaMultiThread.md index 67def19..ba3743f 100644 --- a/docs/JavaMultiThread.md +++ b/docs/JavaMultiThread.md @@ -3,6 +3,7 @@ #### [1.进程与线程的区别是什么?](#进程与线程的区别是什么?) #### [2.进程间如何通信?](#进程间如何通信?) + #### [3.Java中单例有哪些写法?](#Java中单例有哪些写法?) #### [4.Java中创建线程有哪些方式?](#Java中创建线程有哪些方式?) #### [5.如何解决序列化时可以创建出单例对象的问题?](#如何解决序列化时可以创建出单例对象的问题?) diff --git a/docs/Lock.md b/docs/Lock.md index ecafef3..1f1fb21 100644 --- a/docs/Lock.md +++ b/docs/Lock.md @@ -230,26 +230,30 @@ ReentrantLock的非公平锁与公平锁的区别在于非公平锁在CAS更新s **不同点:** -1.实现原理 +**1.实现原理** -synchronized是一个Java 关键字,synchronized锁是JVM实现的,底层代码应该是C++代码。而ReenTrantLock是JDK实现的,是Java提供的一个类库,代码是Java代码,源码实现更加方便阅读。 +synchronized是一个Java 关键字,是由JVM实现的,底层代码应该是C++代码。而ReentrantLock是JDK实现的,是Java提供的一个类库,代码是Java代码,源码实现更加方便阅读。 -2.性能 +**2.性能** -在以前,synchronized锁的实现只有重量级锁一种模式,性能会比较差,后面引入了偏向锁和轻量级锁后就优化了很多。 +在以前,synchronized锁的实现只有重量级锁一种模式,性能会比较差,后面引入了偏向锁和轻量级锁后就优化了很多。根据测试结果,在线程竞争不激烈的情况下,ReentrantLock与synchronized锁持平,竞争比较激烈的情况下,ReentrantLock会效率更高一些。 -3.功能 +**3.功能** -synchronized只能修饰方法,或者用于代码块,而ReenTrantLock的加锁和解锁是调用lock和unlock方法,更加灵活。 +synchronized只能修饰方法,或者用于代码块,而ReentrantLock的加锁和解锁是调用lock和unlock方法,更加灵活。 -其次是synchronized的等待队列只有一个(调用wait()方法的线程会进入等待队列),而ReenTrantLock可以有多个条件等待队列。可以分组唤醒需要唤醒的线程们,而不是像synchronized要么用notify方法随机唤醒一个线程要么用notifyAll方法唤醒全部线程。ReenTrantLock 提供了一种能够中断等待锁的线程的机制,就是线程通过调用lock.lockInterruptibly()方法来加锁时,一旦线程被中断,就会停止等待。 +其次是synchronized的等待队列只有一个(调用wait()方法的线程会进入等待队列),而ReentrantLock可以有多个条件等待队列。可以分组唤醒需要唤醒的线程们,而不是像synchronized要么用notify方法随机唤醒一个线程要么用notifyAll方法唤醒全部线程。ReentrantLock 提供了一种能够中断等待锁的线程的机制,就是线程通过调用lock.lockInterruptibly()方法来加锁时,一旦线程被中断,就会停止等待。 -ReenTrantLock可以使用tryLock(long timeout, TimeUnit unit)方法来尝试申请锁,设置一个超时时间,超过超时时间,就会直接返回false,而不是一直等待锁。 +ReentrantLock可以使用tryLock(long timeout, TimeUnit unit)方法来尝试申请锁,设置一个超时时间,超过超时时间,就会直接返回false,而不是一直等待锁。 -4.公平性 +ReentrantLock可以响应中断,而synchronized锁不行 + +**4.公平性** synchronized锁是非公平锁,ReentrantLock有公平锁和非公平锁两种模式。 +https://www.codercto.com/a/22884.html + ### ReentrantLock的加锁流程是怎么样的? ReentrantLock非公平锁的加锁流程: @@ -276,6 +280,8 @@ ReentrantLock非公平锁的加锁流程: https://blog.csdn.net/qq_14996421/article/details/102967314 +https://blog.csdn.net/fuyuwei2015/article/details/83719444 + ### 谈一谈你对AQS的理解? AQS是AbstractQueuedSynchronizer的缩写,是一个抽象同步队列类,可以基于它实现一个锁,例如ReentrantLock,只是需要实现tryAcquire()方法(也就是获取资源的方法,判断当前线程能否申请到独占锁)和tryRelease()方法(也就是释放资源的方法,在线程释放锁前对state进行更新),AQS会根据tryAcquire()的返回结果,来进行下一步的操作, diff --git a/docs/MySQLNote.md b/docs/MySQLNote.md index 4d1574c..04c8b6b 100644 --- a/docs/MySQLNote.md +++ b/docs/MySQLNote.md @@ -1066,6 +1066,43 @@ https://blog.csdn.net/dennis211/article/details/78170079 因为大查询在查询时可能会锁住很多数据,也需要获取到这些数据的行锁才能进行查询,切分成小查询可以减少锁竞争,减少等待获取锁的时间。 +##### 1.使用show profile对一条SQL查询分析当前会话中语句执行的资源消耗情况 + +1.profiling配置默认是不开启的,可以使用set profiling = ON;命令将配置暂时打开。 + +2.执行一条查询SQL + +3.使用show profiles可以查看最近15条查询SQL及对应的查询idquery id + +4.假设查询id为9,使用这个命令show profile for query 9;可以查看每个步骤及其消耗的时间。 + +``` +mysql> show PROFILE for QUERY 9; ++----------------------+----------+ +| Status | Duration | ++----------------------+----------+ +| starting | 0.000054 | +| checking permissions | 0.000007 | +| Opening tables | 0.000116 | +| init | 0.000019 | +| System lock | 0.000009 | +| optimizing | 0.000004 | +| statistics | 0.000011 | +| preparing | 0.000010 | +| executing | 0.000002 | +| Sending data | 0.000061 | +| end | 0.000005 | +| query end | 0.000006 | +| closing tables | 0.000006 | +| freeing items | 0.000031 | +| cleaning up | 0.000010 | ++----------------------+----------+ +``` + +https://www.cnblogs.com/116970u/p/11004431.html + +https://www.jianshu.com/p/1efdddf3d461 + ### char类型与varchar类型的区别? char类型 diff --git a/docs/Nginx.md b/docs/Nginx.md index 6caa9c5..31c2a19 100644 --- a/docs/Nginx.md +++ b/docs/Nginx.md @@ -375,4 +375,7 @@ Demo3.抢购场景降级 3)(integer)14 # 漏斗剩余容量 4)(integer)-1 # 被拒绝之后,多长时间之后再试(单位:秒)-1 表示无需重试 5)(integer)2 # 多久之后漏斗完全空出来 -``` \ No newline at end of file +``` + + + diff --git a/docs/RedisBasic.md b/docs/RedisBasic.md index c2075a4..e5634f2 100644 --- a/docs/RedisBasic.md +++ b/docs/RedisBasic.md @@ -247,6 +247,17 @@ http://blog.csdn.net/lzb348110175/article/details/98941378 https://xie.infoq.cn/article/b3816e9fe3ac77684b4f29348 +### epoll水平触发和边缘触发的区别? + +**水平触发**和**边缘触发**两种: + +- LT,默认的模式(水平触发) 只要该fd还有数据可读,每次 `epoll_wait` 都会返回它的事件,提醒用户程序去操作, +- ET是“高速”模式(边缘触发) + + 只会提示一次,直到下次再有数据流入之前都不会再提示,无论fd中是否还有数据可读。所以在ET模式下,read一个fd的时候一定要把它的buffer读完,即读到read返回值小于请求值或遇到EAGAIN错误 + +epoll使用“事件”的就绪通知方式,通过`epoll_ctl`注册fd,一旦该fd就绪,内核就会采用类似回调机制激活该fd,`epoll_wait`便可收到通知。 + ### 同步与异步的区别是什么? 同步与异步的区别在于调用结果的通知方式上。 同步执行一个方法后,需要等待结果返回轮询调用结果才能继续执行,然后继续执行下去。 diff --git a/docs/RedisDataStruct.md b/docs/RedisDataStruct.md index dc0f8f2..5cd40d6 100644 --- a/docs/RedisDataStruct.md +++ b/docs/RedisDataStruct.md @@ -23,6 +23,10 @@ Redis中的简单动态字符串其实是对C语言中的字符串的封装和 2.频繁修改一个字符串时,会涉及到内存的重分配,比较消耗性能。(Redis中的简单动态字符串会有内存预分配和惰性空间释放)。 +**如果字符串实际使用长度len<1M**,实际分配空间=len长度来存储字符串+1字节存末尾空字符+len长度的预分配空闲内存 + +**如果字符串实际使用长度len>1M**,实际分配空间=len长度来存储字符串+1字节存末尾空字符+1M长度的预分配空闲内存 + 所以Redis中的简单动态字符串结构,除了包含一个字符数组的属性,还包含数组的长度,数组的实际使用长度等属性,通过增加长度属性,可以保证字符串是二进制安全的,从而可以保存任意类型的数据,例如一张图片,对象序列化后的数据等等。 ##### 字符串使用场景如下: diff --git a/docs/Rule.md b/docs/Rule.md new file mode 100644 index 0000000..0d5e10a --- /dev/null +++ b/docs/Rule.md @@ -0,0 +1,78 @@ +##### 1.使用BigDecimal替代Float和Double + +主要Float和Double是使用类似于科学计数法那样"有效数字+指数"来表示的,所以在二进制存储时,是会丢失精度,没法做到精准的。所以浮点数之间不能使用==等值判断,浮点数包装类型之间不能使用equals + +```java +float a = 1.0f - 0.9f; +float b = 0.9f - 0.8f; //通过debug调试发现这两次减运算减下来,a和b的值存在一些差异,不是一模一样的,丢失了精度 +Boolean result = a == b;//结果是false + +Float x = 1.0F - 0.9F; +Float y = 0.9F - 0.8F; +Boolean result = x.equals(y);//结果是false +``` + +解决方案: + +1. 任何货币金额,均以最小货币单位且整型类型来进行存储。例如在数据库里面存10000,代表是100.00元。 + +2. 使用Bigdecimal来存这些值,并且进行加减。 + +```java +BigDecimal a1 = new BigDecimal("1.0"); +BigDecimal b1 = new BigDecimal("0.9"); +BigDecimal c1 = new BigDecimal("0.8"); + +BigDecimal a2 = a1.subtract(b1); +BigDecimal b2 = b1.subtract(c1); + +System.out.println(a2.equals(b2));//打印结果是true +``` + + + +2.布尔类型的变量,都不要加is前缀,否则部分框架解析会引起序列化错误。 + +一般假设我们定义一个Boolean变量为isHot,按照Bean规范生成的get方法应该是isIsHot,但是我们使用IDEA来自动生成get方法时,生成的是isHot()方法, + +> JavaBeans规范中对这些均有相应的规定,基本数据类型的属性,其getter和setter方法是getXXX()和setXXX,但是对于基本数据中布尔类型的数据,又有一套规定,其getter和setter方法是isXXX()和setXXX。但是包装类型都是以get开头。 + +```java +private boolean isHot; +public boolean isHot() { + return isHot; +} +public void setHot(boolean hot) { + isHot = hot; +} +``` + +这样子在实例对象转json时,序列化框架看到isHot()方法会去找hot实例变量,这样就会找不到变量值。 + +在与前端交互时,同意需要注意,避免Boolean类型参数是is前缀开头的,因为Spring MVC在接受参数时,看到前端json传过来的值是isHot,而set方法中没有setIsHot()方法,只有setHot()方法 + +https://www.cnblogs.com/goloving/p/13086151.html + +https://blog.csdn.net/qq_31145141/article/details/71597608 + +##### 正确的加锁方式 + +通过这种方式来加锁,保证抛出异常时可以正常解锁,同时lock()方法不能在try代码块中调用,防止线程还没有加上锁时抛出异常,然后进行解锁,抛出IllegalMonitorStateException异常(对未加锁对象调用释放锁tryRelease()方法就会抛这个异常)。 + +```java +Lock lock = new XxxLock(); // ... +lock.lock(); +try { + doSomething(); + doOthers(); +} finally { + lock.unlock(); +} +``` + +##### COUNT(*)与count(列名) + +1.【强制】不要使用count(列名)或count(常量)来替代count(*),count(*)是SQL92定义的标 准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。 + 说明:count(*)会统计值为 NULL 的行,而 count(列名)会将NULL值排除掉,不会统计此列为 NULL 值的行。 + +2.count(distinct col) 计算该列除 NULL 之外的不重复行数 \ No newline at end of file diff --git a/docs/ZooKeeper.md b/docs/ZooKeeper.md index a28cfb4..b916bc3 100644 --- a/docs/ZooKeeper.md +++ b/docs/ZooKeeper.md @@ -37,12 +37,18 @@ C得票超过半数,C成为leader,之后加入的D,E也只会投给C。 每个节点都会投给自己,然后选票发给其他节点 ##### 2.处理选票信息 从其他节点B收到投票信息后,进行处理 + 2.1 如果本节点的逻辑时钟小于接受这条投票的逻辑时钟, + 说明本节点之前错过了上一轮的投票,将当前存储的选票信息清空, + 2.2 如果本节点的逻辑时钟大于接受的这条投票的逻辑时钟,那么忽略掉这条投票信息。 + 2.3 本节点的逻辑时钟等于接受的这条投票的逻辑时钟,那么进行处理,与本节点当前投票的结果进行比较 先比较ZXID(数据ID,越大代表数据越新),ZXID越大的应该当leader,ZXID相同比较SID,SID越大的当leader。 + 2.4如果比较的结果跟当前节点的投票结果不一致,那么需要更改选票,将更改后的选票结果发送给其他节点。 + 2.5 将其他节点B的投票结果记录下来 ##### 3.统计选票 diff --git a/docs/linux.md b/docs/linux.md index a069cf3..c56e09c 100644 --- a/docs/linux.md +++ b/docs/linux.md @@ -15,4 +15,26 @@ https://www.cnblogs.com/aspirant/p/11543456.html ### 僵尸进程和孤儿进程是什么? 僵尸进程就是子进程调用exit退出或者是运行时发生致命错误,结束运行时,一般会把进程的退出状态通知给操作系统,操作系统发送SIGCHLD信号告诉父进程“子进程退出了”,父进程一般会使用wait系统调用以获得子进程的退出状态,这样内核就可以在内存中释放子进程了,但是如果父进程没有进行wait系统调用,子进程就会驻留在内存,成为僵尸进程。 -孤儿进程就是父进程退出,但是它的子进程还在进行,这些子进程就会变成孤儿进程,被init进程(进程号为1)所收养,由它来管理和收集子进程的状态。由于孤儿进程有init进程循环的wait()调用回收资源,所以不会产生什么危害。 \ No newline at end of file +孤儿进程就是父进程退出,但是它的子进程还在进行,这些子进程就会变成孤儿进程,被init进程(进程号为1)所收养,由它来管理和收集子进程的状态。由于孤儿进程有init进程循环的wait()调用回收资源,所以不会产生什么危害。 + +##### Linux指令使用 + +统计access.log中ip访问次数前十的 + +``` +cat access.log | awk '{ print $1}' | sort -n | uniq -c | sort - r |head 10 +``` + +统计当前目录下(包含子目录) java 的文件的代码总行数。 + +``` +wc -l `find . -name "*.java"` | awk '{ sum=sum+$1 } END { print sum }' +``` + +### Linux进程间通信的方式? + +《Linux 的进程间通信》 https://zhuanlan.zhihu.com/p/58489873 + +浅析进程间通信的几种方式(含实例源码) https://zhuanlan.zhihu.com/p/94856678 + +https://mp.weixin.qq.com/s/WgZaS5w5IXa3IBGRsPKtbQ \ No newline at end of file diff --git a/index.html b/index.html index 05c83a1..a1aa2b7 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - 《后端技术总结》 + 《大厂面试指北》 @@ -14,7 +14,7 @@