1、内存溢出和内存泄露的区别
内存溢出:(Out Of Memory---OOM)
系统已经不能再分配出你所需要的空间,比如你需要100M的空间,系统只剩90M了,这就叫内存溢出。
内存泄漏: ( Memory Leak )
强引用所指向的对象不会被回收,可能导致内存泄漏,虚拟机宁愿抛出OOM也不会去回收他指向的对象。
内存溢出的原因及解决方法:
- 内存溢出原因:
1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
4.使用的第三方软件中的BUG;
5.启动参数内存值设定的过小 - 内存溢出的原因及解决方法:
- 修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
- 检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
- 对代码进行走查和分析,找出可能发生内存溢出的位置。
- 使用内存查看工具动态查看内存使用情况
重点排查以下几点:
1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
2.检查代码中是否有死循环或递归调用。
3.检查是否有大循环重复产生新对象实体。
4.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
5.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
2、线程池开的数量,是通过什么去选定的,线程池为什么要关闭?
最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
1、CPU密集型
尽量使用较小的线程池,一般Cpu核心数+1
因为CPU密集型任务CPU的使用率很高,若开过多的线程,只能增加线程上下文的切换次数,带来额外的开销
2、IO密集型
方法一:可以使用较大的线程池,一般CPU核心数 * 2
IO密集型CPU使用率不高,可以让CPU等待IO的时候处理别的任务,充分利用cpu时间
方法二:线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
下面举个例子:
比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算得到:((0.5+1.5)/0.5)*8=32。这个公式进一步转化为:
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
3、混合型
可以将任务分为CPU密集型和IO密集型,然后分别使用不同的线程池去处理,按情况而定
线程池关闭的意义不仅仅在于结束线程执行,避免内存溢出,因为大多使用的场景并非上述示例那样 朝生夕死。线程池一般是持续工作的全局场景,如数据库连接池。
我之前看到很多同事写代码,为了提高效率,采用多线程去优化。由为了提高多线程的性能,用到了线程池。
表面上看起来很高大上了,但其实上发现很多人用到了局部变量的线程池,然后使用过后并没有回收,导致了线程泄漏甚至内存溢出。
Executors作为局部变量时,创建了线程,一定要记得调用executor.shutdown();来关闭线程池,如果不关闭,会有线程泄漏问题。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestThread {
public static void main(String[] args) {
while (true) {
ExecutorService service = Executors.newFixedThreadPool(1);
try {
service.submit(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
});
} catch (Exception e) {
}finally{
service.shutdown();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
3、Linux软链接和硬链接?
硬链接和软链接也有它们的一些特性
- 软链接 (符号链接) ln -s source target
- 硬链接 (实体链接)ln source target
硬链接的特性:
①文件有相同的 inode 及 data block
②只能对已存在的文件进行创建
③不能对交叉文件系统进行硬链接的创建
④不能对目录进行创建,只可以对文件进行创建
⑤删除一个硬链接文件,并不会影响其他拥有相同 inode 值的文件
软链接的特性:
①软连接有自己的文件属性及权限等
②可对不存在的文件或目录创建软链接
③软链接可以交叉文件系统
④软链接可以对文件或目录进行创建
⑤创建软链接的时候,链接计数 i_nlink 不会增加(这个可以看一下 Linux 内核中关于 inode 结构体的定义)
⑥删除软链接并不影响被指向文件,但若被指向的原文件被删除,则相关链接被称为 “死链接”(即 dangling link)。此时,若被指向文件被重新创建,死链接便恢复为软链接
4、Mybatis怎么防止注入?
<select id=“getBlogById“ resultType=“Blog“ parameterType=”
int
”><br>
select id,title,author,content from blog where id=#{id}
</select>
mybatis启用了预编译功能,在sql执行前,会先将上面的sql发送给数据库进行编译,执行时,直接使用编译好的sql,替换占位符“?”就可以了。因为sql注入只能对编译过程起作用,所以这样的方式就很好地避免了sql注入的问题。
mybatis是如何做到sql预编译的呢?其实在框架底层,是jdbc中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的sql语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行一个sql时,能够提高效率,原因是sql已编译好,再次执行时无需再编译。
5、Redis里数据丢失了怎么办,Redis和Mysql怎么实现同步?
一、对强一致要求比较高的,应采用实时同步方案,即查询缓存查询不到再从DB查询,保存到缓存;更新缓存时,先更新数据库,再将缓存的设置过期(建议不要去更新缓存内容,直接设置缓存过期)。
二、对于并发程度较高的,可采用异步队列的方式同步,可采用kafka等消息中间件处理消息生产和消费。
三、使用阿里的同步工具canal,canal实现方式是模拟mysql slave和master的同步机制,监控DB bitlog的日志更新来触发缓存的更新,此种方法可以解放程序员双手,减少工作量,但在使用时有些局限性。
四、采用UDF自定义函数的方式,面对mysql的API进行编程,利用触发器进行缓存同步,但UDF主要是c/c++语言实现,学习成本高。
6、切换root用户和普通用户,在服务器上运行是用的root权限吗
如果要切换到root用户,只需要简单的执行命令 "sudo su" 即可。
退出root也很简单,只要执行exit命令,就可以退回到user用户。
7、spring和springboot区别
SpringBoot不是Spring官方的框架模式,而是一个团队在Spring4.0版本上二次开发并开源公布出来的。简而言之,SpringBoot就是一个轻量级,简化配置和开发流程的web整合框架,我们可以说是因为SpringBoot才有了Spring这么火。
那么SpringBoot和Spring有什么区别呢?
Spring Boot可以建立独立的Spring应用程序;
内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说可以直接跑起来,用不着再做部署工作了;
无需再像Spring那样搞一堆繁琐的xml文件的配置;
可以自动配置(核心)Spring。SpringBoot将原有的XML配置改为Java配置,将bean注入改为使用注解注入的方式(@Autowire),并将多个xml、properties配置浓缩在一个appliaction.yml配置文件中。
提供了一些现有的功能,如量度工具,表单数据验证以及一些外部配置这样的一些第三方功能;
整合常用依赖(开发库,例如spring-webmvc、jackson-json、validation-api和tomcat等),提供的POM可以简化Maven的配置。当我们引入核心依赖时,SpringBoot会自引入其他依赖。