三个JAVA臭皮匠

Java常见问题记录

2018-07-15  本文已影响33人  后厂村老司机

前言

本篇记录一些常见问题

1:常见的OOM场景有哪些?

A:java.lang.OutOfMemoryError: Java heap space

堆空间不足以给进入老年代的对象分配空间,可以通过Xmx调整大小解决。
新生对象在Eden区分配内存,Eden区满了之后YGC会把Eden区存活的对象放到Survivor区,Survivor区分为From和To,每次GC都会检查Eden和From把存活的复制到To然后From和To换名称。当Eden和Survivor都无法分配或者对象已经成功躲过几轮YGC的时候对象会被处理到老年代,下面的例子一直创建对象,占满新生代之后请求在老年代分配对象空间,如果老年代空间也不够了就会抛出这个错误!

public class HeapOOM {
    
    static class OOMObject {
    }
    
    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        
        while (true) {
            list.add(new OOMObject());
        }
    }
}

B:java.lang.OutOfMemoryError: PermGen space

堆空间无法给新的类的Meta信息和类的Class对象分配空间,可通过调整-XX:MaxPermSize大小解决。
一般Spring动态代理生成过多的字节码类或者有大量的类被加载进入内存的时候会出现这个错误,JSP预编译的时候也会出现这个错误!错误的主要原因是YGC和FGC都不会堆永久代进行垃圾清理。

C:java.lang.StackOverflowError

线程请求的栈深度大于虚拟机分配给线程的栈空间和方法栈的大小大于线程栈空间的时候会出现这个错误!
虚拟机栈和本地方法栈是线程独立的内存,外加一个程序计数器,每当新建线程的时候JVM都会给线程分配这三个内存作为栈空间。
无限递归就会出现这个问题

public class StackOverflowErrorMain {
    int stackLength = 0;

    public StackOverflowErrorMain() {
    }

    public void addStackLength(){
        stackLength++;
        addStackLength();
    }

    public static void main(String[] args){
        StackOverflowErrorMain sofem = new StackOverflowErrorMain();
        try {
            sofem.addStackLength();
        }catch (Throwable e){
            System.out.println(sofem.stackLength);
            e.printStackTrace();
        }
    }
}

D:OutOfMemoryError: unable to create new native thread

无法给新的线程分配栈空间就会出现这个问题!
一直创建线程可以复现。

E:OutOfMemoryError: GC overhead limit exceeded

通过统计GC时间来预测是否要OOM了,提前抛出异常,防止OOM发生,可以通过调整Xmx来解决问题。
GC的对象过多的时候JVM预测GC的时间会很长,98%的时间用来回收2%内存,这个时候就会抛出异常。

F:OutOfMemoryError:Requested array size exceeds VM limit

数组过大,请求分配空间的时候堆内存不足以满足,检查是不是数组size过大或者提高Xmx堆内存大小解决这个问题

G:OutOfMemoryErr java.io.FileInputStream.readBytes(Native Method)

堆内存分配的过多,占用了总内存的80%以上导致本地内存没有空间了

H:OutOfMemoryError: request <size> bytes for <reason>. Out of swap space?

其他进程耗尽内存的时候会出现这个错误。

2、MinorGC和FullGC的触发条件

A:MinorGC触发条件

B:FullGC触发条件

3、Java有内存泄漏吗?什么情况内存泄漏?

A:Java中有内存泄漏

内存泄漏是指无用对象得不到GC的及时回收导致长时间占用内存,从而造成内存空间的浪费。
一般场景是一个长生命周期的对象持有短生命周期对象的引用

B:可达性分析:

对象如果到GCRoot没有任何引用连相连的时候,说明这个对象可回收,回收过程分为两次,第一次筛选出覆盖finalize方法的对象放到F-Queue中,虚拟机会调用线程执行这个方法,如果F-Queue中第二次被标记,那么第二次垃圾回收的时候就会回收掉。可以作为GCRoot的对象有

4、TCP三次握手过程

A:首先了解为什么要进行三次握手?

为了客户端和服务器确保自己有接收信息和发送信息的能力

B:三次握手过程

客户端C发送链接请求到服务端,此时C不知道自己有没有收发能力
服务端S接收到C的连接请求并返回一个消息,此时S知道自己有接收消息的能力,不知道自己发送消息的能力
客户端接收到服务端的响应,此时客户端知道自己有发送消息和接收消息的能力,客户端发送确认指令给服务端
服务端接收到客户端响应信息,确认了自己发送信息的能力,至此三次握手成功确认了双方收发信息的能力。

C:三次握手重要概念

D:图解TCP三次握手

第一次主动打开连接的是客户端,所以SYN标志位为1,ACK为0(不是响应),字节流序号seq=x
第二次服务器接收到链接请求,ACK标志位为1(是一个响应),SYN=1(重新打开一个连接),字节流序号为y,ack=x+1(C发来的字节流序号基础上加一位表示是刚刚客户端你传过来的流数据)
第三次,客户端收到SYN=1和ACK=1之后知道这是一个响应和一个新连接,并通过ack=x+1知道这个响应是基于自己刚刚的字节流的;客户端要对这个连接进行确认ACK=1,seq=x+1(表示是第一次握手之后的下一个数据),ack=y+1(表示回复的信息是刚刚你传过来的信息).握手完成


TCP三次握手过程

E:TCP四次挥手

第一次,客户端请求断开连接,FIN=1,seq=u
第二次,服务端接收到FIN标志知道要断开连接,ACK=1,seq=v,ack=u+1,确认收到了断开请求
第三次,服务端准备断开准备就绪,FIN=1,ACK=1,seq=w ack=u+1,告知客户端自己已经就绪了,你也可以准备断开了
第四次,客户端收到FIN=1,被告知断开连接,通过ACK和ack=u+1知道这是自己第一条消息的恢复,ACK=1,seq=u+1,ack=w+1,响应服务端,自己已经OK。四次挥手完成。
客户端最后又等待2MSL,为了确保最后一个ACK能够到达服务器
服务端发送两次,因为FIN表示自己不再发送数据了,但是可能接受数据,此时服务端数据可能没发送完呢,第一次告诉客户端我这还有数据,别着急,第二次就是请求断开了


image.png

5、死锁的四个必要条件

A:如何预防

6、StringBuffer和StringBuilder的区别

7、HashMap原理

8、事务的隔离级别

A:四种隔离级别

9、类加载器工作机制

public static int value=1000;//赋值为0
public static final int value=1000;//赋值为1000,字面量
CONSTANT_Class_info
CONSTANT_Field_info
CONSTANT_Method_info

等引用的目标可能不在内存里;直接引用指的是指向目标的指针或者相对偏移量等能够定位到目标的句柄,引用的目标已经在内存里

1、通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
2、定义对象数组,不会触发该类的初始化。
3、常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。
4、通过类名获取Class对象,不会触发类的初始化。
5、通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。
6、通过ClassLoader默认的loadClass方法,也不会触发初始化动作。

类加载过程
双亲委派机制

10、Java锁的原理

synchronized关键字,在JVM中编译的时候会在同步块前后形成监视进入和监视退出两个字节码,这两个字节码都需要一个引用类型的参数来指定要锁定和解锁的对象,如果指定的话就会使用指定的对象,如果不指定就看是类方法还是对象方法。在执行监视进入的指令的时候,会判断能否进入,进入成功后锁计数器+1,不成功则继续等待和其他线程竞争,执行退出指令的时候会把锁计数器变为0。

11、SpringAOP的原理

12、SpringMVC的主要流程

web.xml中配置一个DispatcherServlet负责分派转发,请求到来的时候直接打到DispatcherServlet上的doService方法,doService调用doDispatch方法根据request找到相应的Handler,Handler处理完成之后把ModelAndView对象返回给前端渲染


image.png

13、创建线程有几种方式

package com.ccfdod.juc;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 一、创建执行线程的方式三:实现Callable接口。相较于实现Runnable接口的方式,方法可以有返回值,并且可以抛出异常
 * 二、执行Callable方式,需要FutureTask实现类的支持,用于接收运算结果
 */
public class TestCallable {
    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        // 1.执行Callable方式,需要FutureTask实现类的支持,用于接收运算结果
        FutureTask<Integer> result = new FutureTask<>(td);
        new Thread(result).start();
        // 2.接收线程运算后的结果
        Integer sum;
        try {
            //等所有线程执行完,获取值,因此FutureTask 可用于 闭锁
            sum = result.get();
            System.out.println("-----------------------------");
            System.out.println(sum);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class ThreadDemo implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i <= 100000; i++) {
            System.out.println(i);
            sum += i;
        }
        return sum;
    }
}

14、事务的隔离级别

事务隔离级别

A:每种隔离级别的实现方式

B:InnoDB锁机制

C、MVCC是啥?

D、InnoDB中的锁种类

E、为什么要有意向锁?

F、什么时候会加锁?

G:INNODB只有通过索引条件检索数据的时候才会使用行级锁,否则使用表锁!!!!注意是整条记录都没有索引的时候

15、Redis常见问题

A:memcached和Redis的区别

B:Redis常见性能问题和解决方案

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据

C、Redis事务

D、WATCH命令实现CAS乐观锁

WATCH mykey
  val = GET mykey
  val = val + 1
  MULTI
  SET mykey $val
  EXEC

16、Zookeeper常见问题

17、有关基本类型float 、int、double、short

18、HashMap在JDK1.7和JDK1.8有什么区别

HashMap为什么不是线程安全的?

多个线程同时put的时候可能造成某个key值Entry Key List的死循环,进而导致cpu100%,当另外一个线程get这个EntryList死循环的key的时候也会一直执行,导致线程越来越多,终极原因就是导致了死循环而不是死锁。
多个线程同时put可能导致两个线程同时做rehash当调用到transfer方法的时候可能出现闭环

19、数据库索引及其实现方式

A:索引有哪些优缺点?

B:索引类型

C:索引的实现方式

20、幻读的理解

21、可重复读是怎么实现不管其他事务是否提交自己读取到的数据都不变的?

A:MVCC机制

22、Serializable是给表加表锁吗?

Serializable是对同一行记录不管是增删改查都不能同时进行,加的是行锁并不是表锁!

23、synchronized的实现原理

同步代码块是通过使用monitorenter和monitorexit指令实现的,同步方法依靠的是方法修饰符上的ACC_SYNCHRONIZED实现的

24、Zookeeper选举流程

A:几个重要指标

B:选举消息内容

投票完成之后,需要把投票信息发送给集群中所有服务器,内容为
服务器ID,数据ID,逻辑时钟,选举状态

C:初始启动选举

D:崩溃恢复选举

E:3台挂1台能工作吗?挂2台呢?

F:集群支持动态添加机器码?

25、mybatis原理

26、Https原理

27、Tomcat原理

28、偏向锁,锁膨胀,锁升级

29、设计模式代码实现

30、redis底层有序集合的实现方式

31、数据结构与算法,二叉树的种类

32、怎么保证切面编程切入的顺序

33、mybatis一二级缓存与sqlsession有什么关系?什么时候开启,什么时候关闭?

34、IOC怎么解决循环依赖?

35、JDK1.8有哪些新特性?

上一篇 下一篇

猜你喜欢

热点阅读