OPPO面试面经

第一次面试给了OPPO
效果不是很满意,感觉自己开始上来状态就不行,紧张的自我介绍都结结巴巴,太需要克服这点了,然后后面面试官问的题偏数据库较多一点,但恰巧这边我只是会增删改查,毫无理论可言,虽说面试官问的知识点我都看过之前,有些没答上来,有些答的时候还是答的不够全面,条理也不够清晰,另外自己总是带一些,好像是。。。。,可能是这个。。。的字眼,自我感觉非常的不好,哎,不开心。

Mysql常用的存储引擎

MyISAM是MySQL存储引擎之一,不支持数据库事务、行级锁、和外键。因此在INSERTUPDATE数据即写操作时需要锁定整个表,效率会很低

InnoDB为MySQL提供了事务支持、回滚、崩溃修复能力、多版本并发控制、事务安全的操作。

InnoDB有什么特性

InnoDB引擎特点

1.支持事务,支持4个事务隔离级别,支持多版本读。

2.行级锁定(更新时一般是锁定当前行),通过索引实现,全表扫描仍然会是表锁,注意间隙锁的影响。

3.读写阻塞与事务隔离级别相关。

4.具有非常高效的缓存特性:能缓存索引,也能缓存数据。

5.整个表和主键以Cluster方式存储,组成一个平衡树。

6.所有Secondary Index都会保存主键信息。

7.支持分区,表空间,类似oracle数据库。

8.支持外键约束,5.5之前不支持全文索引,5.5之后支持外键索引。

小结:supports transactions,row-level locking。and foreign keys

9.和Myisam引擎比,Innodb对硬件资源要求比较高。

MySQL引擎之innodb引擎应用场景及调优

Innodb引擎适用的生产场景

1、需要事务支持的业务(具有较好的事务特性)

2、行级锁定对高并发有很好的适应能力,但需要确保查询时通过索引完成。

3、数据读写及更新都较为频繁的场景,如:bbs,sns,微博,微信等。

4、数据一致性要求较高的业务,例如:充值转账,银行卡转账。

5、硬件设备内存较大,可以利用Innodb较好的缓存能力来提高内存利用率,尽可能减少磁盘IO。

B+树索引和hash索引使用的场景

B+树是一个平衡的多叉树。B+树从根节点到叶子节点的搜索效率基本相当,不会出现大幅波动。

哈希索引采用一定的哈希算法,把键值换成新的哈希值,检索时不需要类似B+树那样从根节点逐级查找,只需一次哈希算法即可立刻定位到相应的位置。

创建索引有什么技巧吗 (没答上来)

  • 经常检索排序大表中30% 或非排序表7%的行,建议建索引;
  • 为了改善多表关联,索引列用于联结;
  • 列中的值比较惟一;
  • 列中有许多空值,不适合建立索引;
  • 经常一起使用多个字段检索记录,组合索引比单索引更有效;
  • 不要索引大型字段;
  • 不要索引常用的小型表,尤其假如它们有频繁的插入和删除操作;
  • 不能真正使用到索引的情形:在索引列上使用函数查询,使用模式匹配LIKE,使用IN子查询;

事务的隔离级别

读未提交 读已提交 可重复读 序列化

读已提交解决脏读问题

可重复读解决不可重复读问题

序列化解决幻读问题。

MySQL的默认隔离级别是可重复读

Oracle的默认隔离级别是读已提交

SQL Server的默认隔离级别是读已提交

redis有哪些基本的数据类型

Redis支持5种数据类型:String(字符串)hash(哈希)list(列表)set(集合)zset(有序集合)

  • String

    一个key对应一个value

    String类型是二进制安全的,因此redisstring可以包含任何数据,比如jpg图片或者序列化对象

    String类型的值最大能存储512MB

    常用命令:getsetdecrincrmget

  • hash

    hash是一个键值对集合:是一个String类型的fieldvalue的映射表

    hash特别适合用于存储对象

    每个hash可存储2^(32-1)键值对

    常用命令:hgethsethgetall

  • list

    list是一个简单的字符串列表、按照插入顺序排序,你可以添加一个元素到列表的头部或者尾部

    list类型经常会被用于消息队列的服务、以完成多程序之间的消息交换

    列表最多可存储2^(32-1)个元素

    常用命令:lpushrpushlpoprpoplrange

  • set

    set也是一个字符串列表,和列表不同的是,在插入和删除时会判断是否存在了该元素。集合的最大的优势在于可以进行交集并集差集操作。集合是通过hash表实现的,因此,添加,删除,查找的复杂度都是o(1)

    应用场景:

    • 利用交集求共同好友。
    • 利用唯一性,可统计访问网站的所有独立IP
    • 好友推荐的时候根据tag求交集,大于某个thresold就可以推荐

    集合最多可存储2^(32-1)个元素

    常用命令:saddspopsmemberssunion

  • zset

    set一样是String类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数却可以重复。

    应用场景:

    • 例如存储全班同学的成绩,其集合value可以是同学的学号、而score就可以是成绩
    • 排行榜应用,根据得分列出topN的用户等。

    常用命令:zaddzrangezremzcard

Redis的持久化策略

Redis的持久化策略有两种:

  • RDB:快照形式是直接把内存中的数据保存到一个dump文件中,定时保存。

  • AOF:把所有的对Redis的服务器进行修改的命令都存在一个文件里,命令的集合

  • RDB的优缺点

  • 优点:

    • 对性能的影响最小,Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客服端请求的效率
    • 每次快照都会生成一个完整的数据快照文件,所以**可以辅助其他手段保存多个时间点的快照(**例如把每天0点的快照备份至其他存储媒介中)
    • 作为非常可靠的灾难恢复手段。使用RDB文件进行数据恢复要比使用AOF要快很多。
  • 缺点:

    • 快照是定期生成的,所以在Redis crash时或多或少会丢失一部分数据
    • 如果数据集非常大且cpu不够强(比如单核cpu),Redisfork子进程时可能会消耗相对较长的时间,影响Redis对外提供服务的性能。
  • AOF的原理

    AOF提供了三种fsync配置,always/everysec/no,通过配置项[appendfsync]指定:

    appendfsync no:不进行fsync,将flush文件的时机交给OS决定,速度最快

    appendfsync always:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢

    appendfsync everysec:折中的做法,交由后台线程每秒fsync一次

    随着AOF不断地记录写操作日志,因为所有的操作都会记录,所以必定会出现一些无用的日志。大量无用的日志会让AOF文件过大,也会让数据恢复的时间过长。不过Redis提供了AOF rewrite功能,可以重写AOF文件,只保留能够把数据恢复到最新状态的最小写操作集。

    AOF rewrite可以通过BGREWRITEAOF命令触发,也可以配置Redis定期自动进行:

    auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb

    上面两行配置的含义是,Redis在每次AOF rewrite时,会记录完成rewrite后的AOF日志大小,当AOF日志大小在该基础上增长了100%后,自动进行AOF rewrite。同时如果增长的大小没有达到64mb,则不会进行

  • AOF的优缺点

  • 优点:

    • 最安全在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。
  • 缺点:

    • AOF文件通常比RDB文件更大性能消耗比RDB高数据恢复速度比RDB慢

      Redis的数据持久化工作本身就会带来延迟,需要根据数据的安全级别和性能要求制定合理的持久化策略:

      AOF + fsync always的设置虽然能够绝对确保数据安全,但每个操作都会触发一次fsync,会对Redis的性能有比较明显的影响AOF + fsync every second是比较好的折中方案

      不过大多数应用场景下,建议至少开启RDB方式的数据持久化。Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的RDB 文件。

redis的过期策略

1.设置过期时间

  • expire key time—这是最常用的方式
  • setex(String key,int seconds,String value) —字符串独有的方式

注意:

  • 除了字符串自己独有设置过期时间的方法外,其他方法都需要依靠expire方法来设置时间
  • 如果没有设置时间,那缓存就是永不过期
  • 如果设置了过期时间,之后又想让缓存永不过期,使用persist key

2.三种过期策略

  • 定时删除

    • 含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除
    • 优点:保证内存被尽快释放
    • 缺点:
      • 若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key
      • 定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重
      • 没人用
  • 惰性删除

    • 含义:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null。
    • 优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)
    • 缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)
  • 定期删除

    • 含义:每隔一段时间执行一次删除过期key操作
    • 优点:
      • 通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用–处理"定时删除"的缺点
      • 定期删除过期key–处理"惰性删除"的缺点
    • 缺点
      • 在内存友好方面,不如"定时删除"
      • 在CPU时间友好方面,不如"惰性删除"
    • 难点
      • 合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)(这个要根据服务器运行情况来定了)

3.Redis采用的过期策略

惰性删除+定期删除

  • 惰性删除流程
    • 在进行get或setnx(当key不存在时设置value)等操作时,先检查key是否过期
    • 若过期,删除key,然后执行相应操作
    • 若没过期,则直接执行相应操作
  • 定期删除流程(简而言之,就是对指定个数的数据库的每一个库随机删除小于等于指定个数的过期key)
    • 遍历每个数据库(redis.conf中配置的database数量,默认为16)
      • 检查当前库中的指定个数个key(默认每个库检查20个key,相当于循环下面的操作20次)
        • 如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历
        • 随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key
        • 判断定期删除操作是否已经到达时长,若已经到达,直接退出定期删除。
  • 注意
    • 对于定期删除,在程序中有一个全局变量current_db来记录下一个将要遍历的库,假设有16个库,我们这一次定期删除遍历了10个,那此时的current_db就是11,下一次定期删除就从第11个库开始遍历,假设current_db等于15了,那么之后遍历就再从0号库开始(此时current_db==0)

4.RDB对过期key的处理

过期key对RDB没有任何影响

  • 从内存数据库持久化数据到RDB文件
    • 持久化key之前,会检查是否过期,过期的key不进入RDB文件
  • 从RDB文件恢复数据到内存数据库
    • 数据载入数据库之前,会对key先进行过期检查,如果过期,不导入数据库(主库情况)

5.AOF对过期key的处理

过期key对AOF没有任何影响

  • 从内存数据库持久化数据到AOF文件:
    • 当key过期后,还没有被删除,此时进行执行持久化操作(该key是不会进入aof文件的,因为没有发生修改命令)
    • 当key过期后,在发生删除操作时,程序会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉)
  • AOF重写
    • 重写时,会先判断key是否过期,已过期的key不会重写到aof文件

StringBuilder和StringBuffer

主要有线程安全缓冲区性能三方面的区别

  • 线程安全方面

    • StringBuffer:线程安全的。StringBuilder:线程不安全。因为StringBuffer的所有公开方法都是synchronized修饰的,而StringBuilder并没有sychronized修饰。
  • 缓冲区方面

    StringBuffer每次获取toString都会直接使用缓存区的toStringCache值来构造一个字符串。

    StringBuilder则每次都需要复制一次字符数组,再构造一次字符串

    所以、StringBuffer对缓冲区进行了优化。

  • 性能方面

    由于StringBuilder没有加锁,所以性能要优于StringBuffer

  • 总结:

    StringBuffer适用于多线程操作同一个StringBuffer的场景,StringBuilder在单线程场景下更为合适

LinkedList和ArrayList的区别

ArrayList底层是基于数组实现的,查询效率较高,增删改查的效率较低。

LinkedList底层是基于链表实现的,查询效率较低,增删速度较快

两者都不是线程安全的

concurrentHashMap

因为在多线程环境下,使用HashMap进行put操作可能会引起死循环,导致cpu利用率接近100%,所以在并发情况下不能使用HashMap

因此针对这一问题:出现了Hashtable 和concurrentHashMap

  • hashtable

    Hashtable使用synchronized来保证线程安全,但在线程竞争激烈的情况下,hashtable的效率非常低下。因为在同一时刻只能有一个线程占有资源,其他线程都处于等待状态。

  • concurrentHashMap

    concurrentHashMap采用分段锁的思想,将数据分成一段一段存储,然后给每一段数据配上一把锁,当一个线程占用锁访问其中一段数据时,其他线程也可以访问别的段数据。

  • 总结

    Hashtable的任何操作都会把整个表锁住,是阻塞的。好处是总能获取最实时的更新,比如说线程A调用putAll写入大量数据,期间线程B调用get,线程B就会被阻塞,直到线程A完成putAll,因此线程B肯定能获取到线程A写入的完整数据。坏处是所有调用都要排队,效率较低
    ConcurrentHashMap 是设计为非阻塞的。在更新时会局部锁住某部分数据,但不会把整个表都锁住。同步读取操作则是完全非阻塞的。好处是在保证合理的同步前提下,效率很高坏处是严格来说读取操作不能保证反映最近的更新。例如线程A调用putAll写入大量数据,期间线程B调用get,则只能get到目前为止已经顺利插入的部分数据。
    应该根据具体的应用场景选择合适的HashMap。

sychronized和lock有什么区别

区别:

  • 底层实现:sychronized是Java中的关键字,是由JVM来维护的,是JVM层面的锁 lock是一个类,是java代码层面的锁底层实现的

  • 使用方式不同:sychronized在使用时候,获取锁和释放锁,都是由系统维护的。而使用lock的需要手动获取锁,手动释放锁。

  • 异常的处理方式:sync在线程发生异常时会自动释放锁,不会发生异常死锁,Lock异常时不会自动释放锁,所以需要在finally中实现释放锁。

  • 等待是否可中断:sychronized是不可中断的,除非抛出异常或者正常运行完成,Lock是可以中断的,中断方式有:

    • 调用设置超时方法tryLock(long timeout,timeUnit unit)
    • 调用lockInterruptibly()放到代码块中,然后调用interrupt()方法可以中断
  • 加锁的时候是否可以公平:sync是非公平锁,lock既可以公平也可以不公平

  • 锁可以绑定多个条件

    sync:要么随机唤醒一个线程,要么是唤醒所有等待的线程

    lock:用来实现分组唤醒所需要唤醒的线程,可以精确的唤醒线程。

  • 从锁的实现机制来看

    sync采用的是独占锁,也就是悲观锁的机制

    lock采用的是乐观锁,所谓乐观锁就是每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。

volatile关键字

volatile,用来将变量的更新操作通知到其他线程,当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将改变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

img

当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。

而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。

当一个变量定义为volatile之后,将具备两种特性:

​ 1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,

2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

volatile 性能:

volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

线程池处理任务的流程

线程池刚被创建时,只是向系统申请一个用于执行线程队列和管理线程池的线程资源,在调用execute()添加一个任务时,线程池会按照以下流程执行任务:

(1): 如果正在运行的线程数量小于corePoolSize(核心线程数量),线程池就会立刻创建线程并执行该线程任务

(2):如果正在运行的线程数量大于等于corePoolSize,该任务就将被放入阻塞队列中。

(3):在阻塞队列已满且正在运行的线程数量少于maximumPoolSize时,线程池会创建非核心线程立刻执行该线程任务

(4):在阻塞队列已满且正在运行的线程数量大于等于maximumPoolSize时,线程池将拒绝执行该线程任务并抛出RejectExecutionException异常

(5):在线程执行任务完毕后,该任务将被从线程池队列中移除,线程池将从队列中取下一个线程任务继续执行。

(6):在线程处于空闲状态的时间超过keepAliveTime时间时,正在运行的线程数量超过corePoolSize,该线程将会被认定为空闲线程并停止。因此在线程池中所有线程任务都执行完毕后,线程池会收缩到corePoolSize大小。

TCP三次握手的流程

在这里插入图片描述

第一次握手:主机A发送位码SYN=1;随机产生seq number=1234567的数据包到服务器,主机BSYN=1知道,A要求建立联机;

第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机Aseq+1)SYN=1ACK=1,随机产生seq=7654321

第三次握手:主机握手后检查ack number是否正确,即第一次发送的seq number+1,以及位码ACK是否为1,若正确,主机A会再发送ack number=(主机B的seq+1) ACK=1;主机B收到后的确认seq值与ACK=1,则连接建立成功。

OSI七层模型

OSI七层模型:

  • 物理层:IEEE802.1A IEEE802.2到IEEE 802.11
  • 数据链路层:FDDIEthernet Arpanet PDN SLIP PPP
  • 网络层:IPICMPARPRARPAKPUUCP
  • 传输层:TCPUDP
  • 会话层:SMTPDNS
  • 表示层:SNMPTelnetRloginGopher
  • 应用层:HTTPFTPSMTPWAIS
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OPPO嵌入式面试题是一项技术能力评估的工具,旨在了解申请者对嵌入式开发领域的理解和技能水平。以下是对该问题的回答: 嵌入式系统是指嵌入在其他设备或系统中,而不是独立存在的计算机系统。它的主要特点是体积小、功耗低、集成度高、功能特定化。常见的应用领域包括手机、智能家居、汽车、工控机等。 作为一名嵌入式开发工程师,我需要具备以下能力和技能: 1. 熟悉嵌入式系统的工作原理和体系结构,掌握常见的微控制器或微处理器的原理和特性,能够根据需求选择合适的芯片。 2. 熟悉C/C++等编程语言,具备嵌入式软件的开发经验,并能够进行硬件和软件的接口设计与开发。 3. 掌握嵌入式系统的调试和测试技术,能够使用调试工具和仪器对硬件和软件进行故障排除。 4. 熟悉常用的通信协议,如串口、I2C、SPI、CAN等,并能够进行通信协议的设计和开发。 5. 具备硬件设计和电路原理的基础知识,能够进行简单的电路设计和原理图绘制。 6. 了解操作系统的工作原理和实时系统的设计,能够进行系统资源管理和任务调度。 7. 具备良好的问题解决能力和团队合作精神,能够在项目中解决实际问题并与团队成员合作完成任务。 通过这些技能和能力的积累,我相信自己能够胜任嵌入式开发工程师的工作。并且我也意识到嵌入式系统的发展受到硬件和软件的共同影响,因此我会不断学习和提升自己的能力,以满足日益复杂和多样化的嵌入式系统需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值