腾讯——面经2

HashMap和TreeMap?

   HashMap中的元素是无序的,TreeMap中的元素是有序的,HashMap的底层是哈希表,TreeMap的底层是红黑树,所以,HashMap适用于添加删除查询操作,TreepMap适用于按自然顺序或按自定义顺序的查询操作,HashMap可以通过调整负载因子和初始容量来进行调优,而TreepMap总是处于平衡状态所以不需要调优

mysql热备份原理?

   也就是主从复制的原理:master将更改记录写入binary log中,然后slave将binary log中的数据读取到自己的relay log中,再重做一次relay log中的事件从而实现了热备份

虚拟内存和物理内存?

  物理内存:是真实的内存(内存条)

  虚拟内存:磁盘空间中的一块逻辑内存

  以前只有物理内存的时候,每次开启一个进程都要给4G的物理内存,这样就导致很容易就将内存分配完,而没有分配到资源的进程就只有等待,引入虚拟内存后一个进程运行时得到的是4G的虚拟内存,实际上可能只占用一点物理内存,这4G是进程自己以为自己获得的,实际用了多小内存就对应多少物理内存而不是直接4G的物理内存

扫描二维码关注公众号,回复: 10192767 查看本文章

jvm和jmm?

  jvm:是java虚拟机,内存结构分为方法区,堆,虚拟机栈,本地方法栈,程序计数器

  jmm:是java内存模型,主要规定了线程和内存之间的一些关系,即所有变量都储存在主内存中,对于所有变量都是共享的,但是每个线程也有自己的工作内存用来保存主存中某些变量的拷贝,线程对变量的操作在工作内存中进行,变量的传递需要通过主内存完成

  自我感觉jmm中的主内存对应堆,工作内存对应栈,假如是创建一个数组并进行赋值,那么操作如下:主内存(堆)为数组分配内存空间,线程将数组复制到工作内存中进行赋值操作,操作完成后再将数据刷新回主内存中,目的就是保证数据一致性

对servlet的认识?

  servlet是用java编写的服务端程序,主要是用于交互式的浏览和修改数据,生成动态的web内容,它就是一个运行了请求/响应服务器中的网络模块。它是单例的,然后通过重写doGet或者doPost来响应请求

   具体生命周期:首先由url请求触发,然后ClassLoader加载相关类,接下来实例化,初始化,然后调用服务(doGet,doPost),最后destroy

ThreadLocal?

   当使用ThreadLocal维护变量时,会为每一个使用该变量的线程提供一个独立的变量副本,这样同时多个线程访问该变量并不会彼此影响,所以不存在线程安全问题,但是会有多余的资源消耗

  与线程同步机制相比的优势:它为每一个线程提供独立的变量副本,隔离了多个线程对数据的访问冲突,因为每一个线程都有自己独立的副本,所以就不比进行变量同步了。其实ThreadLocal就是采用了用空间换时间的方式,而同步机制采用了用时间换空间的方式。

  底层:底层就是维护了一个ThreadLocalMap,key是那个ThreadLocal类型的变量,value是我们指定的值。

sql注入和解决方式?

  sql注入就是指用户所输入的内容在sql语句拼接过程中使逻辑发生变化而产生了新的sql语句(比如加上个or或者and)

 解决方案:使用预编译sql语句进行参数的传递。比如用PrepareStatement,我们先把语句固定好,然后将其中的?换成要传递的参数

mysql的join的理解?

  join的实现是靠的嵌套循环算法实现的,它会将驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中去查询数据,然后合并结果

springmvc和spring?

 spring是ioc和aop的容器框架,而springmvc是基于spring的web框架,springmvc依赖于spring,spring就是包含了很多开源项目的总称,springmvc是其中的一个开源项目。

redis的单线程模型?

  redis是用c写的单进程单线程的,它直接在内存中进行操作所以速度特别快,它通过队列的方式将并发访问转换成了串行访问,同时为了提高io的效率,使用了多路复用,是通过监视多个io流的状态实现的多路复用

tcp状态转换过程?

  三次握手:首先处于close状态,然后服务器进入listen状态开始监听,接着客户端发送syn给服务器,客户端进入syn_sent状态,服务端收到syn后,返回ack给客户端,自己进入syn_recv状态,客户端收到ack后,再发送ack给服务端,自己进入establish状态,服务端接收到ack后,自己也进入establish状态

   四次挥手:客户端发送fin给服务端,自己进入fin_wait_1状态,客户端收到服务端的ack后,再进入fin_wait_2状态,收到了服务端的fin后,客户端发送ack给服务端,自己进入time_wait状态

time_wait的原因:为了使客户端最后发送的ack能够到达服务端,还有一个目的就是让在网络中的报文都消失掉

redis为什么采用跳表而不是红黑树?

   因为在做范围查找时,红黑树比跳表操作要复杂,在红黑树上,找到指定范围的小值之后,还需要通过中序遍历继续寻找不找过大值的节点,而跳表进行范围查找就比较简单,它只需要在找到小值后,进行遍历就可以实现了。而且红黑树的插入删除操作可能会导致树结构的调整,而跳表只需要删除或者添加节点就行了。

僵尸进程和孤儿进程?

    僵尸进程:子进程先于父进程退出后,子进程的pcb需要其父进程释放,但是父进程并没有释放子进程的pcb,这样的子进程就是僵尸进程,也就是其实已经死掉的进程

    孤儿进程:一个父进程退出后,它的一个或多个子进程还在运行,这些进程就会成为孤儿进程,会被init进程收养,并由init进程对他们完成状态进行收集工作

   区别:孤儿进程由于父进程已经死亡,所以系统会帮助处理孤儿进程,所以不占用资源,而僵尸进城占用着资源

50亿个int类型的正整数,怎么去重?

   采用bitmap,把数据放在bitmap中,然后遍历每次判断bitmap中是否有该值

内存碎片?

   内存碎片通常分为内部碎片和外部碎片

       内存碎片:由于采用了固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,内存碎片不能完全避免

       外部碎片:由于某些未分配的连续内存区域太小,以至于不能满足任意进程的内存分配请求,从而不能被进程利用的内存区域

       现在采用的是段页式内存分配,将进程的内存区域分为不同的段,然后将每一段由多个固定大小的页组成,通过页表机制,使段内的页不必连续处于同一块内存区域,从而减少了外部碎片,但是仍然可能存在少量的内部碎片

udp不可靠,那么怎么保证数据的实时性?

    udp不需要三次握手四次挥手等机制,所以传输数据非常快,它只负责将数据发送出去,所以只要网络速度够快,那么就能够保证实时的,但是可能通讯质量并不是那么高

堆和栈的区别?

   堆空间的内存是动态分配的,一般存放对象,并且需要手动释放内存。栈空间是由系统自动分配的,一般存放局部变量,会自动释放。堆申请的空间更大,栈空间比较小,堆上创建对象比较慢,因为空间是连续的,栈上创建对象比较快

线程之间的通信?

    共享变量,主要通过wait,notify,notifyAll方法

    队列(也就是生产者消费者的模式进行通信)

进程之间的通信?

   信号量,消息队列,共享内存,管道

select和epoll?

    select和epoll都是I/Od多路复用模型,用于持续监听多个socket的

    select:会轮询各个socket,不管socket是否活跃,随着socket数量的增加,性能会主键下降

     epoll:采用了中断注册回调的方式,socket io就绪时发出中断,然后将socket加入就绪队列,它能够显著提高程序在大量并发连接中只有少量活跃的情况下的cpu利用率,epoll使用了内存映射技术将内核和用户控件指向同一块内存

    select的缺点:内核/用户数据拷贝频繁,操作复杂,轮询时间效率低

   epoll的优点:插入句柄时返回速度特别快,还能够有效的将发生事件的句柄给用户

Linux查看进程cpu使用率的命令?

   top

   top然后再输入1,就是查看每个核心的cpu使用率

tcp流模式与udp报文模式的区别?

  tcp是基于字节流的,当发送端发送数据时,接收端可以不必一次接收完,而是分几次接收,也可以发送方发送几次,然后接收端一次接收完,但是发送端发送的数据量不能大于对方的流量控制

   udp是发送一次,接收端就必须接收一次,如果缓冲区小于报文长度,那么多出的部分会被抛弃

   不同的原因是因为:tcp是面向连接的,在连接持续的过程中,服务端收到的数据都是由同一台主机发出的,这个时候就不存在数据劫持问题,只要保证数据有序到达就行。

                                   而udp是无连接的,只要知道接收端的ip和端口号,任何主机都能向接收方发送数据,所以是发送一次就接收一次

如何实现哈希表?

   哈希表是通过数组+链表实现的,首先通过对应的key的hashcode找到对应的数组下标,然后就能获得value值了,假如同一个hashcode下有多个元素,那么就可以通过链表,将元素放在链表的下一个节点。

epoll水平触发和边缘触发?

  水平触发:只要读内核缓冲区非空,有数据可以读取,就会一直发出可读信号,只有有空间可以写入,那么就会一直发出可写信号,LT模式支持阻塞和非阻塞两种,epoll默认的模式就是LT

   边缘触发:当读内核缓冲区由空转换为非空时,发出可读信号通知,当写内核缓冲区由满转换为不满的时候发出可写信号进行通知。

    两者的区别就是水平触发只要读缓冲区有数据,就会一直发出可读信号,而边缘触发仅仅在非空变为空时才发出一次可读信号

36辆自动赛车和6条跑道,没有计时器的前提下,最少几次比赛可以筛选出最快的3辆车?

   8次

  

标记清除算法?

   标记清除算法是一种两阶段对对象进行回收的算法

     第一阶段:标记,从根节点出发遍历对象,对访问过的对象打上标记,表示对象可达

     第二阶段:清除,对于那些没有被标记的对象进行回收

  期间对象的内存分配:标记清除算法中新建对象分配内存时假设大小为size,那么需要对空闲列表(free_list)进行一次单向遍历找出大于等于size 的块,有三种分配策略:

                                              1.First_list:找到大于等于size的块后立即返回

                                               2.Best_fit:遍历整个空闲列表,返回大于等于size的最小分块

                                              3.Worst_fit:遍历整个空闲列表,找到最大的分块,切成两部分,一部分是size,然后返回该部分

        推荐使用first_fit,因为worst_fit会形成内存碎片

redis持久化?

   redis的持久化主要分为快照持久化(RDB)和AOF持久化

   快照持久化会进行定期存储,保存的是数据本身,aof持久化是每次修改数据时同步到硬盘,保存的是数据的变更记录

   rdb优点:存储文件紧凑,适用于备份和容灾恢复,并且最大化了redis的性能

         缺点:如果redis没有正常关闭,那么此时到上个快照点之间的所有数据都会丢失

   AOF优点:由于是日志追加文件,所以不需要定位,就算redis异常关闭也可以通过redus-check-aof工具修复,当aof文件很大时redis会在后台自动重写

          缺点:对于同样的数据,aof文件通常更大,并且速度可能会比rdb慢,aof通过递增方式更新数据,而rdb从头开始创建,所以rdb更加健壮和稳定(更适合备份)

线上出现502问题怎么排查?

   502错误一般是由于后台服务器挂掉了,这时候排查可以从cpu的使用情况,数据库的连接数量,内存情况这几个方面去排查 

hashMap为什么初始值大小为16,链表长度到达8变为红黑树,为6又变成链表?

  hashMap每次扩容都是以2的整数次幂进行扩容的,设置为16能够保证计算后的index即可以是奇数又可以是偶数,这样的话只要传进来的key足够分散,那么按位与的时候获得的index就会减少重复,从而减少了hash碰撞的几率。而如果是8或者4的话容易导致map扩容影响性能,而分配得更大的话又浪费资源。所以目的就是:减少哈希碰撞,提高map查询效率,分配过小则会频繁扩容,分配过大则浪费资源。

     8变为红黑树,6变为链表的原因:1.红黑树的查询效率是logn,当为8时如果是链表的话查询的平均长度是4,而红黑树log(8)是3,并且当节点数量越多红黑树的查询优势越明显。2:Treenode占用空间是普通node的两倍,所以只有当包含足够多的节点时才会转换成Treenode,而当节点变少使又会变成普通的node,8和6应该就是空间和时间的权衡情况下做出的决定,好像是通过泊松分布得到的

dubbo的负载均衡算法及优缺点?

   随机,轮询,最少活跃数,一致性hash算法

   随机算法:在一个截面上碰撞的概率较高,但调用量越大分布就越均匀

   轮询算法:它假设所有的服务器的处理性能都相同,不去关心每台服务器的当前连接数和响应速度,所以当请求服务间隔时间变化较大时,轮询算法容易导致服务器间的负载不平衡

  最少活跃调用数算法:导致慢的提供者接收的请求更少

分布式服务治理?

  1.比如dubbo有版本号机制,可以用于灰度发布

   2.灵活的负载均衡和路由策略

  3.熔断机制用来避免整个分布式系统产生雪崩

如何检测进程是否出现了内存泄漏?

   可以通过pmap命令来查看

分布式系统的强一致性和最终一致性?

    强一致性:当更新操作完成后,后续的任何进程或线程的访问都会返回最新的更新的值,也就是总是能够读取到最新写入的值,但是需要牺牲可用性

    最终一致性:允许数据之间有延迟,但是最终的数据要是一致的,也就说并不要求任意时刻所有节点的数据都相同,但是随着时间的迁移,会趋于相同(DNS系统就是最终一致性,修改dns记录后不会在全球所有dns服务节点生效,而是等待dns服务器缓存过期后才更新)

Linux下如何找出io读写很高的进程?

  通过iostat查看相关磁盘的使用信息,然后通过iotop找到占用高的进程

集群脑裂?

   由于网络问题导致master节点和slave节点无法互相感知到,这个时候slave节点会升级成为master节点,就会出现两个master节点,这个时候如果客户端还基于原来的master节点继续写入数据,那么新的master节点是无法同步这些数据的,当网络问题解决后,如果要从新的master中同步数据就会造成大量数据的丢失

 redis的解决方案:设置连接到master的最小slave数量和最大延迟时间。如果slave数量小于设置的值并且延迟时间小于最大延迟时间那么master会拒绝掉写请求。这样的话就算出现脑裂,也不会写入新的数据,就能够减少数据同步之后的数据丢失了

Linux的异步io?

  三种方式实现:1.read/write

                            2.AIO(父进程clone出子进程帮助它做io,完成后通过signal或callback通知父进程,这样在用户看来就算aio了,其实实际上还是sio)

                            3.mmap

mysql的容灾策略?

   1.主从复制

   2.使用mysqldump实现从逻辑角度完全备份mysql,然后配合二进制日志备份实现增量备份

   3.使用lvm从物理角度几乎完全的热备份,配合二进制日志备份实现增量备份

一个ip和海量ip黑名单,怎么判断ip是否在黑名单中?

   使用布隆过滤器。它有一个位数组和k个哈希函数,我们先使用k个哈希函数对这个ip进行k次计算,就能够得到k个哈希值了,然后根据得到的哈希值去判断位数组中对应下标的值是否为1,如果都为1,那么就在布隆过滤器中,只要有一个不为1,那么就不在。但是布隆过滤器可能存在误判(也就是说如果某个元素存在,那么可能是误判,但是某个元素不在,那么就一定不在)。这个时候可以通过设置白名单来结果误判的问题

     不适用位图的原因是因为位图法所占空间随着集合内最大元素的增大而增大,假如查找的元素数量少但是值特别大,那么就会特别浪费空间

海量数据找中位数?

     首先对海量数据进行分份,然后遍历每一份中的所有数据,每个数据用位运算去除最高的8位,然后根据最高的8位的值确定放入哪个桶里,再把每个桶写入一个磁盘文件中,并且统计每个桶内数据的数量,计算中位数是在哪个桶中,再把该桶中的数据读到内存中,以内存中整数的次高8bit又进行一次桶排序,和第一步相同的操作,一直这样知道字节是(0——7bit),这个时候再在内存中进行一次快排就行了

发布了208 篇原创文章 · 获赞 0 · 访问量 5957

猜你喜欢

转载自blog.csdn.net/qq_40058686/article/details/104893103