面试

231 阅读6分钟

or索引:

where 语句里面如果带有or条件, myisam表能用到索引, innodb不行

使用or的列必须都有独立单列索引,否则索引失效,造成全表扫描

使用union来代替or索引

排序:

所排序数组的数值在一定范围内使用桶排序

乐观锁,悲观锁:

乐观锁是是认为当前数据没有被别人修改,但是在更新的时候回去判断一下值有没有被修改,使用于多读的应用场景。

悲观锁是每次访问数据时都会认为别人会修改数据,所以会对数据加锁,被人想访问数据就必须阻塞到它获得锁。

java中的悲观锁是用synchronize关键字来实现,数据库中则行锁和表锁,读锁,写锁

Java中的乐观锁是使用cas来实现,数据库则是使用多版本MVVM来实现


cas缺点:

ABA问题,线程1获取A,线程2将A改成B,然后再改成A,线程1执行,并不知道已发生过改变。

例子:单链表问题

自旋时间过长开销大

只能保证一个共享变量的操作,如果要操作多个共享变量可以将他们封装为对象


synchronize缺点:

一个线程持有锁会导致其他线程发生阻塞,加锁,释放锁会导致大量的上下文切换和性能开销


cas和synchronize使用场景:

对于资源竞争线程比较少的时候,使用synchronize对资源上锁,会导致阻塞和唤醒切换以及用户态和内核态的切换,会消耗额外的cpu资源,而cas的实现基于硬件,不会需要进入内核和切换线程,自旋的几率也比较小,可以获得较高的性能。


在资源竞争比较激烈的时候,cas自旋的概率就比较大,浪费的资源就比较过,所以性能比synchronize要差


jvm在堆中分配内存:

单线程:

1、指针碰撞,在内存比较规整的情况下(取决于内存的回收策略),分配内存的工作只是将指针移动对象大小的距离即可

2、table

适用于内存不规整的情况下,jvm维护了一个空闲内存的列表,记录了空闲内存的地址和大小,分配内存的时候去列表中查询合适的区域即可

多线程:

由于给对象分配内存时的操作不是原子性的,过程包含查询空闲列表,分配内存,修改空闲类表等等,所以操作是非线程安全的。

解决办法:

1、cas,失败时重试

2、TLAB:jvm事先先给每个线程分配一个缓冲区,在里面给对象进行内存分配,当对象的大小超过这个缓冲区的时候,再使用cas对对象进行分配内存


innodb的聚集索引:

主键索引的叶子节点data保存的是表的数据,mylsam保存的是数据的地址

辅助索引d的叶子节点保存的是主键的值,然后再通过主键索引回表寻找数据。

如果select的列有设置索引可以避免回表查询数据,所以尽量少使用select * 查询频率比较高的列可以设置索引

在mysql中执行查询时,只能使用一个索引,如果我们在每个列分别建索引,执行查询时,只能使用一个索引,mysql会选择一个最严格(获得结果集记录数最少)的索引。所以当使用where和order by的时候,如果是两个不同的索引,则order by不会使用索引


组合索引:

理论上索引对顺序是敏感的,但是mysql会根据情况对列的顺序做出调整,调整成你所设置的索引,所以顺序不影响索引的使用,索引使用要遵守最左匹配原则,带头大哥不能丢,中间小弟不能断,使用最频繁的类放在第一列。

索引不包含nul值得列,并不是说有null值得列就不走索引,而是使用is null 来判断列是否为null值得时候,索引失效??,因为索引不存储null值。

当创建了唯一索引的列,空值是会被当做重复的值导致插入失败,而null值就不会,可以重复插入,null值是占空间的


导致内存溢出的原因:

存在死循环,或者循环过大生成新对象太多

内存泄漏,集合中还保存着对象引用,使用完后没有清空,不能被回收

内存一次性加载数据过多,如一次性从数据库中取太多数据

启动参数内存值设定过小

内存溢出类型:

1 、 java.lang.OutOfMemoryError: PermGen space
JVM 管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在 JVM 启动时创建;非堆是留给 JVM 自己用的,用来存放类的信息的。它和堆不同,运行期内 GC 不会释放空间。如果 web app 用了大量的第三方 jar 或者应用有太多的 class 文件而恰好 MaxPermSize 设置较小,超出了也会导致这块内存的占用过多造成溢出,或者 tomcat 热部署时侯不会清理前面加载的环境,只会将 context 更改为新部署的,非堆存的内容就会越来越多。
2 、 java.lang.OutOfMemoryError: Java heap space
第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间 ( 即 -Xms) 是物理内存的 1/64 ,最大空间 (-Xmx) 是物理内存的 1/4 。如果内存剩余不到 40 %, JVM 就会增大堆到 Xmx 设置的值,内存剩余超过 70 %, JVM 就会减小堆到 Xms 设置的值。所以服务器的 Xmx 和 Xms 设置一般应该设置相同避免每次 GC 后都要调整虚拟机堆的大小。假设物理内存无限大,那么 JVM 内存的最大值跟操作系统有关,一般 32 位机是 1.5g 到 3g 之间,而 64 位的就不会有限制了。
注意:如果 Xms 超过了 Xmx 值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。

解决:

修改启动内存参数,jvm默认为64M,tomcat默认为128M,使用-xms,-xmx设置,一般上线时,-xmx=-xms,防止内存抖动(当jvm可用内存低于40%时,jvm会自动增加内存村,直到达到xmx,当可用内存超过70%时,jvm会减少内存,直到-xms)

代码排查,对是否存在死循环或者大循环进行排查

是否有一次性加载大量数据的操作

判断是否有集合使用完对象没有置空的情况