jvm面试题及答案_jvm 高级面试题及答案 - CSDN
精华内容
参与话题
  • 文章目录1、类加载和实例化2、Java是值传递还是引用传递3、类加载的主要过程4、什么是GC5、简述垃圾回收过程6、内存泄漏7、导致内存泄漏的场景8、Java中堆和栈的区别9、ArrayList、LinkedList、Vector的区别10、...

    文章目录

    1、类加载和实例化

    程序开启的时候 jvm只会把需要的类进行加载 其他的类都是在实例化的时候被隐式加载的
    试用class.forName()可以显示加载类

    2、Java是值传递还是引用传递

    基本数据类型和String类型的数据 都是值传递
    引用数据类型都是引用传递 方法中修改值后 真实的值也会发生变化

    3、类加载的主要过程

    a:装载 导入class文件
    b:链接 检查:检查class文件的正确性 准备:为静态变量分配控件 解析:将符号引用转换为直接引用
    c:初始化 对静态变量和静态代码块执行初始化操作

    4、什么是GC

    Java的垃圾回收机制

    5、简述垃圾回收过程

    对象被创建后 如果被其他方法或者对象调用 引用计数会增加1 GC会根据一定的算法去回收引用计数为0的对象 完成垃圾回收

    6、内存泄漏

    无法被GC回收 又没有被任何对象所引用的一块内存区域

    7、导致内存泄漏的场景

    a:静态集合类 HashMap和Vector 生命周期和程序一样久 不恰当的使用会导致
    b:各种数据库连接 网络连接以及io连接 忘记close
    c:各种监听器 使用后没有删除
    d:变量不合理的作用域

    8、Java中堆和栈的区别

    堆和栈都是内存中存放数据的地方
    栈:基础数据类型和对象的引用变量
    堆:对象真实的内容
    常量池:存放常量的地方

    9、ArrayList、LinkedList、Vector的区别

    都是list数据类型
    ArrayList和Vector底层都是数组实现 不同是Vector线程安全 由于占用连续的存储空间 查询比较快 增删比较慢
    LinkedList底层实现为双向链表结构 查询慢 增删比较快 不需要动态扩容 均匀的分散在内存中

    10、StringBuffer和StringBuilder的区别

    StringBuffer中的所有方法都是synchronized修饰的

    11、HashMap、HashTable、TreeMap区别

    HashMap允许key为null HashTable不允许key值为null HashTable线程安全
    TreeMap是有序的map

    12、synchronized 与 Lock 有什么异同

    synchronized是托管给jvm去执行的 lock是代码中去控制的 使用lock时候 一定要记得unlock 防止死锁

    13、数据库事务隔离级别

    none read_uncommit read_commit repeatedable_read serializable

    14、事务的特性 acid

    原子性:所有操作要么都成功 要么都失败
    一致性:A向B转账 必须保证事务之前前后 AB的总余额保持一致
    隔离性:每个事务都有自己的操作空间 相护不影响
    持久性:事务执行完成后的数据 会被永久保存到数据库中

    15、数据库三范式
    16、union和unionAll的区别

    union是合表后去重 unionAll是简单的合表 并不去重

    17、redis 五种数据结构详解(string,list,set,zset,hash)
    18、redis常用命令

    setEx:设置秒级过期时间
    setNx:键必须不存在才能设置成功 分布式锁实现的一个思路
    setXx:与nx完全相反 键必须存在 才能设置成功

    19、redis中list set zset的区别
    20、redis缓存击穿、雪崩、穿透

    为什么要避免上述问题:每次都会查询数据库 导致缓存失效 失去了缓存的意义
    击穿:热点数据 缓存失效后 大量请求直接进入数据库 导致数据库宕机 解决办法:缓存失效 更新缓存的时候 加锁更新 其他进程等待更新完成后再去读取
    雪崩:同一时间 多个缓存同时失效 导致大面积的请求进到数据库中
    穿透:查询了一个缓存和数据库中都没有的数据 比如id为-1的一条数据 解决方案:每次更新缓存的时候 如果没有从数据库获取到值 也要设置一个缓存

    21、redis备份到磁盘的两个算法

    RDB:bgsave命令 后台进行备份 生成一个rdb文件 不可实时备份
    AOF:append only file 可以进行实时备份 往一个文件中实时追加命令 重启后 再次执行命令即可 开启方式:appendonly yes 默认关闭

    22、kafka常见消息引擎泛型

    a:消息队列模型 多用于处理进程/线程间的通信 生产者(producer)往队列发消息 消费者(consumer)从队列中获取消息 多个消费者监听同一个topic时候 一条消息只能被同一个消费者消费 负载均衡模式
    b:发布/订阅模型 发布者(publisher)将消息发送到对应的topic中 所有的订阅者(subscriber)都可以接收到当前消息

    23、项目中使用的rabbitMQ案例

    a:通过消息队列每5分钟上报一次当前服务的ip和端口到统一的解析平台
    b:通过消息队列实现微信支付预约成功后 推送成功消息到门店大堂叫号机去更新叫号列表

    24、E-R图 实体-联系图(Entity Relationship Diagram)

    矩形:表示一个实体 一张表 一个Java类
    椭圆形:表示实体拥有的属性
    菱形:表示多个实体之间的关系

    25、MyBatis和SpringDataJPA的区别

    a:自动建表
    b:动态sql语句
    c:对多种不同数据库的兼容性

    26、ORM框架映射的实体类中为什么尽量不适用基本数据类型

    使用int时候 由于基本数据类型有默认值 int默认为0 如果表中有为null的数据将无法映射 所以 尽量使用Integer等包装类型

    27、MyBatis中ResultMap和ResultType的区别

    返回结果为一个bean的时候 使用ResultMap进行映射
    返回结果为List的时候 使用ResultType进行映射

    28、SpringCloud服务提供者 服务消费者
    29、JPA动态sql查询支持

    QueryByExampleExecutor:简单的动态查询支持
    JpaSpecificationExecutor:复杂的动态查询支持

    30、Netty使用场景

    IM即时消息
    推送

    31、IO读写流程介绍

    进程缓冲区→内核缓冲区→磁盘
    read/write并不是直接对磁盘进行操作,而是先将修改写到进程所在的进程缓冲区,然后进程缓冲区再和内核缓冲区交互,再到磁盘进行持久化

    32、四种IO模型

    同步阻塞IO(Blocking IO)
    同步非阻塞IO(Non-Blocking IO)
    多路复用IO(IO Multiplexing)
    异步 IO(Asynchronous IO)

    33、阻塞IO和非阻塞IO的区别

    阻塞IO,指的是需要内核IO操作彻底完成后,才返回到用户空间执行用户的操作。阻塞指的是用户空间程序的执行状态。传统的IO模型都是同步阻塞IO。再Java中,默认创建的socket都是阻塞的。
    非阻塞IO,指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间执行用户操作,即处于非阻塞的状态,与此同时内核会立即返回给用户一个状态值。
    简单来说:阻塞是指用户空间(调用线程)一直在等待,而不能干别的事情;非阻塞是指用户空间(调用线程)拿到内核返回的状态值就返回自己的空间,IO操作可以干就干,不可以干,就去干别的事情。

    34、同步IO和异步IO的区别

    同步IO,是一种用户空间和内核空间的IO发起方式。同步是指用户空间的线程是主动发起IO请求的一方,内核空间是被动接受方。异步IO则反过来,是指系统内核是主动发起IO请求的一方,用户空间的线程是被动接受方。
    异步IO,指的是用户空间与内核空间的调用方式反过来。用户空间的线程变成被动接受者,而内核空间成了主动调用者。这有点类似于Java中比较典型的回调模式,用户空间的线程向内核空间注册了各种IO事件的回调函数,由内核去主动调用。

    35、同步阻塞BIO

    阻塞io的特点:在内核进行IO执行的两个阶段,用户线程都是被阻塞了。
    阻塞IO的优点:应用的程序开发非常简单;在阻塞等待数据期间,用户线程挂起。在阻塞期间,用户线程基本不会占用cpu资源。
    阻塞IO的缺点:一般情况下,会为每个连接配备独立的线程,在并发量小的情况下,这样做没有问题。但是,在高并发的应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换的开销非常巨大。因此,阻塞线程在高并发下基本是不可用的。

    36、同步非阻塞NIO

    同步非阻塞的特点:应用程序的线程需要不断的进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就继续轮询,直到完成IO系统调用为止。
    同步非阻塞IO的特点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会被阻塞,实时性较好。
    同步非阻塞IO的缺点:不断地轮询内核,这将占用大量的CPU时间,效率低下。
    总体来说,在高并发应用场景下,同步非阻塞IO也是不可用的。一般Web服务器不适用这种IO模型。这种IO模型一般很少直接使用,二十在其他IO模型中使用非阻塞IO这一特性。在Java的实际开发中,也不会涉及这种IO模型。
    同步非阻塞IO,简称NIO,但是,这里指的不是Java中的NIO,java中的NIO指的是New IO,对应的是四种基础IO模型中的多路复用IO(IO Multiplexing)

    37、多路复用IO(IO Multiplexing)
    38、异步 IO(Asynchronous IO)
    39、Linux设置单进程可以打开百万线程 默认单进程最多开1024个线程

    在/etc/rc.local 开机启动文件中添加下述代码:
    ulimit -SHn 1000000

    40、Java中NIO的三个核心组件

    Channel(通道)
    Buffer(缓冲区)
    Selector(选择器)

    41、开源ZooKeeper客户端Curator
    42、ZooKeeper的四种节点类型

    PERSISTENT:持久化节点
    PERSISTENT_SEQUENTIAL:持久化有序节点
    PHEMERAL:临时节点
    EPHEMERAL_SEQUENTIAL:临时有序节点
    注:临时节点下不能创建子节点,临时节点的声明周期不是永久,跟随客户端连接,客户端会话失效后,临时节点会自动删除

    43、ZK分布式命名使用场景

    分布式API目录:服务注册与发现 provider向zk的节点注册ip和端口暴露服务 消费者获取地址并访问
    分布式ID生成器:单体服务可以利用数据库自增生成主键 分布式环境下 需要使用分布式ID生成器
    分布式节点的命名:分布式系统中 节点(机器)动态扩容时候 为动态节点自动命名

    44、ZK实现ID生成器满足哪些特性

    a:全局唯一:不能出现重复ID
    b:高可用:ID生成系统是基础系统,被许多关键系统调用,一旦宕机,就会造成严重影响

    45、Curator封装ZK分布式事件监听

    a:标准的观察者模式:Watcher
    b:缓存监听模式:Cache
    二者的区别Cache监听机制可以反复注册监听,基于Watcher监听器只能监听一次

    46、Curator几个NodeCache节点缓存监听

    NodeCache:节点缓存可用于ZNode节点的监听
    PathCache:子节点缓存可用于ZNode的子节点的监听
    TreeCache:树缓存时PathCache的增强,不光能监听子节点,还能监听ZNode节点自身

    47、分布式锁原理

    单体服务中,使用jvm内的Synchronized和Lock即可,分布式环境下,多台机器,对应多个jvm,多个进程,因此需要使用统一的分布式锁进行同步操作
    ZK实现分布式锁的核心是:临时有序节点 临时可以防止死锁,有序可以保证同步(InterProcessMutex)

    48、ZK实现分布式锁步骤

    a:所有需要竞争资源的进程,都在ZK一个持久化节点创建一个临时的有序的子节点
    b:每个子节点阻塞并监听自己上一个子节点,如果上一个删除的时候,说明自己可以获取锁进行操作(上一个删除后还要判断下自己是不是最小的节点,如果不是,再去监听自己前一个节点)
    c:如果当前获取锁的节点由于网络原因或者系统故障不可用了,因为是临时节点,连接不可用的时候会自动删除节点,可以有效防止死锁的情况

    49、分布式锁主流实现方案和选型

    a:基于Redis的分布式锁。使用并发量很大、性能要求很高而可靠性问题可以通过其他方案弥补的场景
    b:基于ZooKeeper的分布式锁。适用于高可靠(高可用),而并发量不是太高的场景

    50、为什么要使用缓存

    主要原因是数据库的查询是比较耗时的,而使用缓存能大大节省数据查询的时间

    51、RedisTemplate封装的操作Redis方式

    ValueOperations字符串类型操作API集合
    ListOperations列表类型操作的API集合
    SetOperations集合类型的操作API集合
    ZSetOperations有序集合类型操作API集合
    HashOperations哈希类型操作API集合

    52、Spring缓存相关的注解

    @CachePut:设置缓存,先执行方法,并将执行结果缓存起来
    @CacheEvict :删除缓存,在执行方法前,删除缓存
    @Cacheable:查询缓存,先查询注解中的key是否在缓存中,如果在直接返回缓存值,如果缓存中不存在,执行方法

    53、@CachePut和@Cacheable的区别

    @CachePut负责增加缓存
    @Cacheable负责查询缓存,如果没查到,则将执行方法,并将方法的结果增加到缓存

    54、什么是分布式事务

    简单来说,就是一次大的操作由不同的小操作组成,这些小操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

    55、MySql一般数据达到千万级的数据就得分库分表。
    56、分布式事务CAP定理

    C(一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据来说,如果在某个节点的数据更新了,那么其他节点如果都能读取到这个最新的数据,那么就成为强一致性,如果有某个节点没有读取到,那就是分布式不一致。
    A(可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的相应)。可用性的两个关键一个是合理的时间,一个是合理的相应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的相应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如返回50而不是40。
    P(分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里集群有多台机器,有台机器出现了故障,不影响整个汲取的正常工作。

    57、CAP三者是否可以共有

    CAP三者不能共有,在分布式系统中,网络无法保证100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当繁盛分区故障现象时,为了保证一致性,在这个时候必须拒绝请求,但是A又不允许,那么分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构。
    对于CP来说,放弃可用性,追求一致性和分区容错性,我们的ZooKeeper其实就是追求的强一致性
    对于AP来说,放弃一致性(这里指的是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,后面的BASE也是根据AP来扩展的。

    58、BASE

    BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。是对CAP中AP的一个扩展
    a:基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
    b:软状态:允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是CAP中的不一致
    c:最终一致:最终一致是指经过一段时间后,所有节点数据都将达到一致。
    BASE解决了CAP中理论没有网络延迟,在BASE中用软状态和最终一致,保证了延迟后的一致性。
    BASE和ACID是相反的,他完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。

    59、是否真的需要分布式事务

    尽量减少过度设计,太多团队过度设计,搞的所有人疲劳不堪,而微服务过多就会引出分布式事务,这个时候需要将用到事务的微服务聚合成一个单机服务,使用数据库的本地事务。
    分布式事务的原则是:尽量使用数据库的本地事务,因为分布式事务无论是那种方案都会增加你系统的复杂度,这样的成本实在是太高了,千万不要因为追求某些设计,而引入不必要的成本和复杂度。

    60、通过消息队列实现分布式事务

    参考链接
    表设计:
    生产者:账户余额表、事务记录表
    消费者:账户余额表、消息记录表
    生产者事务流程:
    a:支付宝账户扣除100元
    b:给事务记录表中新增一条事务记录 (a、b两步操作在同一个数据库中,可以保证事务一致性,同时成功,同时失败)
    定时程序流程:
    a:定时扫描生产者事务记录表中状态为未完成的记录,将未完成记录发送到消息队列中
    b:将生产者事务记录表中的状态改为已完成
    消费者事务流程:
    a:从消息队列中获取记录
    b:将消息中未完成记录的事务txId作为主键 报错到事务处理表中(防止由于消息队列故障,导致消息二次消费问题)
    c:将余额宝账户增加100元(b、c两步操作在同一个数据库中,可以保证事务一致性,同时成功,同时失败)

    61、为什么使用消息队列MQ

    解耦:服务A是基础服务,任何新接入的服务都要对接A服务,每个人对接A都需要改代码。
    异步:用户一次请求A、B、C三个服务,每个服务耗时40ms,需要等待120ms,访问A后写入消息队列,避免用户等待。
    削峰填谷:中午12点,用户量最多的时候,服务器压力过大,可以先将请求保存在消息队列中,慢慢处理

    62、subString和split效率问题

    // split效率低于subString
    for (Expression param : expressions) {
    // 获取字段的名称
    String key = param.toString();
    // 字段名字中包含as 使用as名称做key 否则适用.后面字段做key
    int asIndex = key.indexOf(" as “);
    int pointIndex = key.indexOf(”.");
    if (asIndex > -1) {
    key = key.substring(asIndex + 4);
    } else if (pointIndex > -1) {
    key = key.substring(pointIndex + 1);
    }
    /if (key.contains(" as “)) {
    key = key.split(” as “)[1];
    } else if (key.contains(”.")) {
    // 字段中不包含as 带. 使用.后面字段做key
    key = key.split("\.")[1];
    }
    /
    Object value = tuple.get(param);
    map.put(key, value);
    }

    63、守护线程和主线程声明周期关系

    一个进程可以有多个守护线程 可以通过Thread.setDaemon(true)来设置守护线程
    a:虚拟机中可能同时有多个线程运行,只有当所有的非守护线程(通常都是用户线程)都结束的时候,虚拟机的进程才会结束,不管当前运行的线程是不是 main 线程。
    b:main 线程运行结束,如果此时运行的其他线程全部是 Daemon 线程,JVM 会使这些线程停止,同时退出。但是如果此时正在运行的其他线程有非守护线程,这些线程停止,同时退出。但是如果此时正在运行的其他线程有非守护线程,那么必须等所有的非守护线程结束,JVM 才会退出。

    64、Reactor反应器模式

    反应器模式由Reactor反应器线程、handlers处理器两大角色组成:
    a:Reactor反应器线程的职责:负责响应IO事件,并且分发到Handlers处理器
    b:Handlers处理器的职责:非阻塞的执行业务处理逻辑

    65、Connection Per Thread模式

    Connection Per Thread模式,一个线程处理一个连接模式,早期版本的Tomcat服务器,利用这种原理实现;
    对于每一个新的网络连接都会分配给一个线程,每隔线程都独立处理自己负责的输入和输出。
    缺点:对应于大量的连接,需要耗费大量的线程资源,对线程资源要求太高。而且线程的反复创建、销毁、线程的切换也需要代价。因此,在高并发的应用场景下,多线程OIO的缺陷时致命的。
    如果解决:一个有效的路径是使用Reactor反应器模式,用反应器模式对线程的数量进行控制,做到一个线程处理大量的连接。(selectionKey)

    66、ZooKeeper中Leader选举流程

    1、ZooKeepter节点状态
    LOOKING:寻找Leader状态,处于该状态需要进行选举流程
    LEADING:领导者状态,处于该状态的节点说明是角色已经是Leader
    FOLLOWING:跟随者状态,表示Leader已经选举出来,当前节点角色是follower
    OBSERVER:观察者状态,表明当前节点角色是observer(不参与投票)
    2、事务ID
    ZooKeeper状态的每次变化都接收一个ZXID(ZooKeeper事务ID)形式的标记。ZXID是一个64位的数字,由Leader统一分配,全局唯一,不断递增。ZXID展示了所有的ZooKeeper的变更顺序。每次变更会有一个唯一的ZXID,如果ZXID1小于ZXID2说明ZXID1在ZXID2之前发生。
    3、初始化时的选举流程(三台服务器)
    a:zk1启动,一台服务器无法进行leader选举,zk2启动时,此时两台机器可以相护通信,每台都试图找到leader,于是进入leader选举过程。选举过程开始。
    b:每个server发出一个投票。由于时初始情况,zk1和zk2都会将自己作为leader服务器来进行投票,每次投票会包含所推举的服务器的myid和zxid,使用(myid,zxid)来表示,此时的zk1的投票为(1,0),zk2的投票为(2,0),然后各自将这个投票发给集群中的其他机器。
    c:接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
    d:处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行比较,规则如下:
    • 优先检查ZXID。zxid比较大的服务器优先做leader
    • 如果zxid相同,那么就比较myid。myid较大的服务器作为leader服务器
    对于zk1而言,他的投票时(1,0),接收zk2的投票为(2,0),首先会比较两者的zxid,均为0,再比较myid,此时zk2的myid最大,于是zk2胜。zk1更新自己的投票为(2,0),并将投票重新发送给zk2。
    e:统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于zk1、zk2而言,都统计出集群中已经有两台机器接受了(2,0)的投票信息,此时便认为已经选出zk2作为leader。
    f:改变服务器状态。一单确定了leader,每个服务器就会更新自己的状态,如果时follower,那么就变更为FOLLOWING,如果是leader,就变更为LEADING。当新的ZooKeeper节点zk3启动时,发现已经有leader了,不再选举,直接将状态从LOOKING改为FOLLOWING。
    4、集群运行期间,Leader故障后的选举流程(三台服务器)
    a:变更状态。leader挂后,余下的非Observer服务器都会将自己的服务状态变更为LOOKING,然后开始进入leader选举过程。
    b:每个Server会发出一个投票。在运行期间,每个服务器上的zxid可能不相同,此时假定zk1的的zxid为124,zk3的zxid为123;在第一轮投票中,zk1和zk3都会投自己,产生投票(1,123),(3,123),然后各自将投票发送给集群中的所有机器。
    c:接收来自各个服务器的投票。与启动时过程相同。
    d:处理投票。与启动时过程相同。由于zk1事务id大,zk1将会变为leader
    e:统计投票。与启动时过程相同。
    f:改变服务器状态。与启动时相同
    5、大致流程
    • 状态改变为LOOKING
    • 第一票投自己(myid,zxid)
    • 每轮投完进行比较 先比较zxid 比自己大的话 第二轮将票给他
    • 如果出现半数票 则选举结束 票数最大为leader

    67、设计模式

    a:根据使用场景 设置模式分类:
    创建型模式 结构型模式 行为型模式
    b:23种设计模式
    单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
    原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
    工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
    抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
    建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。
    代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
    适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
    桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
    装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。
    外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
    享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
    组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。
    模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
    策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
    命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
    职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
    状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。
    观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
    中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
    迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
    访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
    备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
    解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

    68、TCP三次握手 四次挥手

    1、三次握手
    • 客户端向服务器发送SYN同步报文段,请求建立连接
    • 服务器确认收到客户端的连接请求,并向客户端返送SYN同步报文,表示要想客户端建立连接
    • 客户端收到服务器的确认请求后,处于建立连接状态,向服务器发送确认保温
    客户端是在收到确认请求后,先建立连接
    服务器是在收到客户端的确认后,建立连接
    发起连接请求的一定是客户端
    客户端请求建立连接→服务端确认收到请求→客户端明确建立连接
    2、四次挥手
    • A端向B端发送FIN结束报文段,准备关闭连接
    • B端确认A端的报文,表示自己已经收到对方关闭连接的请求 这段时间,A端停止向服务端发送数据,但是B端可以向A端发送数据,将B端未处理完的任务处理完
    • B端向A端发送FIN结束报文段,准备关闭连接
    • A端确认B端的FIN,进入TIME_WAIT状态,此时A端进程已经退出,但是连接还在
    当B端收到A端的ack之后,先断开连接
    当A端等待2MSL之后,确认的B端收到ack后,再断开连接(MSL报文最大生存事件)
    发起断开连接请求的一段最后要进入有一个TIME_WAIT状态
    发起连接请求的可以是客户端也可以是服务端

    69、RabbitMQ消息队列五种队列

    • 简单队列
    • Work模式
    1个生产者对应n个消费者 一个消息只能被一个消费者消费
    • 发布/订阅模式
    1个生产者对应n个消费者
    每个消费者有自己的队列
    生产者没有将消息直接发送到队列,而是发送到了交换机
    每个队列都要绑定到交换机
    生产者发送的消息,经过交换机,到达队列,实现,一个消息被多个消费者获取的目的
    注:一个消费者队列可以有多个消费者实例,只有其中一个消费者示例会消费
    • 路由模式
    • 主题模式Topics

    #:匹配一个或多个字段
    *:匹配一个字段

    70、MQ使用时候的注意事项

    • 消费者去注册相关Exchange和将Queue绑定到Exchange
    • 生产者只需要注册Exchange并将消息发布到对应的Exchange
    • 一个消费队列可以拥有多个消费者 这些消费者是负载均衡的去处理消息的(多劳多得)模式

    71、HashMap的时间复杂度

    • get()方法最好情况O(1),最差情况O(N),平均O(1)
    • put()方法最好情况O(1),最差情况比较复杂,其中底层实现还涉及到map扩容
    • 最好情况 没出现hash碰撞
    • 最坏情况 所有key的hash值都一样

    72、Spring核心理念

    ioc:控制反转,通过控制反转来管理各类Java资源,从而降低了各种资源的耦合;并且提供了极低的侵入性
    aop:面向切面,通过动态代理技术,允许我们按照约定进行配置编程,进而增强了bean的功能。

    73、SpringBoot的优点

    • 创建独立的Spring应用程序
    • 嵌入的tomcat、jetty或者undertow,无需部署war文件
    • 允许通过maven来根据需要获取starter
    • 尽可能的自动配置Spring
    • 提供生产就绪型功能,如指标、健康检查和外部配置
    • 绝对没有代码生成,对xml没有要求配置

    74、Spring IOC

    IOC容器是一个管理bean的容器,在spring的定义中,他要求所有的ioc容器都需要实现接口BeanFactory,他是一个顶级容器接口。
    在IOC容器中,默认情况下,Bean都是以单例形式存在的,也就是说getBean方法返回的都是同一个对象。
    AnnotationCofingApplicationContext:BeanFactory、ApplicationContext的子类,基于注解的IOC容器。

    75、依赖注入Dependency Injection,DI

    @AutoWired,他注入的机制最基本的一条是:根据类型(by type),根据类型从IOC容器中获取bean。
    使用AutoWired进行依赖注入的时候,如果注入的接口有多于一个的实现类,可一根据变量名称,从IOC容器中获取对象。
    Animal接口 两个实现类:dog、cat
    @AutoWired
    Animal animal; // 报错
    @AutoWired
    Animal dog; // 正常 通过name从IOC容器中获取bean

    76、如果同一接口有多个实现类 该如何对该类型的子类进行依赖注入

    @AutoWired
    @Qualifier(“dog”) // 注入Animal实现类Dog
    Animal animal;

    77、SpringBoot中Bean的生命周期

    • Bean的定义
    • Bean的初始化
    • Bean的生存期
    • Bean的销毁
    spring通过我们的配置,如@ComponentScan定义的扫描路径去找到带有@Component的类,这个过程就是一个资源定位的过程。
    一单找到了资源,那么它就开始解析,并且将定义的信息保存起来。注意此时还没有初始化Bean,也就是没有Bean的实例,它有的仅仅是Bean的定义。
    然后就会把Bean定义发布到SpringIoC容器中。此时IoC容器也只有Bean的定义,还是没有Bean的实例生成。

    78、AOP术语和流程

    • 连接点(join point):对应的是具体被拦截的对象,因为spring只能支持方法,所以被拦截的对象往往就是特定的方法。
    • 切点(point cut):有时候,我们的切面不单单应用于单个方法,也可能是多个类的不同方法,这是,可以通过正则表达式和指示器的规则去定义,从而适配连接点。切点就是提供这样一个功能的概念。
    • 通知(advice):就是i按照约定的流程下的方法,分为前置通知(before advice)、后置通知(after advice)、环绕通知(around advice)、时候返回通知(afterReturning advice)和异常通知(afterThrowing advice),它会根据约定织入流程中,需要弄明白他们在流程中的顺序和运行的条件。
    • 目标对象(target):即被代理对象。
    • 引入(introduction):是指引入新的类和其方法。增强现有bean的功能。
    • 织入(weaving):他是一个通过动态代理技术,为原有服务对象生成代理对象,然后将与切点定义匹配的连接点拦截,并按约定将各类通知织入约定流程的过程。
    • 切面(aspect):是一个可以定义切点、各类通知和引入的内容,spring AOP将通过他的信息来增强bean的功能或者将对应的方法植入流程。

    展开全文
  • JVM面试题及答案

    千次阅读 2018-12-10 16:13:46
    JVM运行时内存区域划分 程序计数器:主要是保存程序执行的下一跳指令的地址 虚拟机栈:主要是处理java代码中的方法,每个方法的执行都会创建一个对应的栈帧,每个方法从开始执行到执行完毕,对应的就是栈帧的出栈和...
    • JVM运行时内存区域划分
    1. 程序计数器:主要是保存程序执行的下一跳指令的地址
    2. 虚拟机栈:主要是处理java代码中的方法,每个方法的执行都会创建一个对应的栈帧,每个方法从开始执行到执行完毕,对应的就是栈帧的出栈和入栈。包含局部变量表,操作数栈,动态链接,方法出口。局部变量表中主要存储基本数据类型以及对象的引用。局部变量表在代码编译期间大小就已经确定。

       会出现两种异常:内存溢出和栈溢出

    当线程请求的栈深度大于虚拟机所容许的最大深度,则会抛出StackOverFlowError异常。如果栈的深度是可以动态变化的,当扩展到无法申请到足够的内存空间时,则抛出OutOfMemeryError

    1. 本地方法栈:Native方法,起作用和java虚拟机栈类似

    以上三个都是线程私有的,垃圾回收器不会回收这三个区域

    1. 方法区:主要存放类信息,常量,静态变量,运行池常量池
    2. 堆:存放对象实例;垃圾回收的主要区域
    • 如何判断对象是否可以回收或存活

    GCRoots:通过一系列名为“GC ROOTS”对象作为起始节点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC ROOTS没有任何引用链相连时,则证明该对象不可用。

    可作为GC ROOTS的对象有一下几种:

    1. java虚拟机栈中的局部变量表中的引用的对象
    2. 方法区的静态属性引用的对象
    3. 方法区的常量引用的对象
    4. 本地方法栈中JNI引用的对象

       但是一次没有引用链相连是不能够确定该对象是一定不可用的,还要看finalize()方法是否有必要执行。该对象没有实现finalize方法或者虚拟机已经调用过该方法,都认为该方法没有必要执行,即回收该对象。如果该对象实现了finalize方法且没使用过,虚拟机则会根据finalize方法中是否有该对象的引用,没有则回收,有了则不回收。(finalize维护一个队列,虚拟机会启动低优先级的线程去执行,但是并不保证该线程能执行完成,目的确保线程的安全)

    • 常见的GC回收算法及其含义
    1. 标记清除:会产生大量的内存碎片
    2. 标记整理:主要用于老年代
    3. 复制算法:内存利用率不高;主要使用在新生代中
    4. 分代算法
    • 常见的JVM性能监控和故障处理工具类:jps、jstat、jmap、jinfo、jconsole等
    •  
    • JVM如何设置参数

    -xx

    -xss

    • JVM性能调优
    • 类加载器、双亲委派模型、一个类的生命周期、类是如何加载到JVM中的
    • 类加载的过程:加载、验证、准备、解析、初始化
    • 强引用、软引用、弱引用、虚引用
    • Java内存模型JMM
    展开全文
  • JVM相关面试题及答案

    万次阅读 多人点赞 2017-03-20 15:47:37
    1. 类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,他们的执行顺序 答:先静态、先父后子。 先静态:父静态 > 子静态 优先级:父类 > 子类 静态代码块 > 非静态代码块 > 构造...

    题目:
    http://www.jsondream.com/2016/12/04/java-interview-question.html

    答案如下:

    1. 类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,他们的执行顺序

    答:先静态、先父后子。
    先静态:父静态 > 子静态
    优先级:父类 > 子类 静态代码块 > 非静态代码块 > 构造函数
    一个类的实例化过程:
    1,父类中的static代码块,当前类的static
    2,顺序执行父类的普通代码块
    3,父类的构造函数
    4,子类普通代码块
    5,子类(当前类)的构造函数,按顺序执行。
    6,子类方法的执行,

    2. JVM内存分配

    这里写图片描述

    这里写图片描述

    3. Java 8的内存分代改进

    从永久代到元空间,在小范围自动扩展永生代避免溢出

    4. JVM垃圾回收机制,何时触发MinorGC等操作

    分代垃圾回收机制:不同的对象生命周期不同。把不同生命周期的对象放在不同代上,不同代上采用最合适它的垃圾回收方式进行回收。
    JVM中共划分为三个代:年轻代、年老代和持久代,
    年轻代:存放所有新生成的对象;
    年老代:在年轻代中经历了N次垃圾回收仍然存活的对象,将被放到年老代中,故都是一些生命周期较长的对象;
    持久代:用于存放静态文件,如Java类、方法等。
    新生代的垃圾收集器命名为“minor gc”,老生代的GC命名为”Full Gc 或者Major GC”.其中用System.gc()强制执行的是Full Gc.
    判断对象是否需要回收的方法有两种:
    1.引用计数
    当某对象的引用数为0时,便可以进行垃圾收集。
    2.对象引用遍历
    果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,gc必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。

    触发GC(Garbage Collector)的条件:
    1)GC在优先级最低的线程中运行,一般在应用程序空闲即没有应用线程在运行时被调用。
    2)Java堆内存不足时,GC会被调用。

    5. jvm中一次完整的GC流程(从ygc到fgc)是怎样的,重点讲讲对象如何晋升到老年代等

    答:对象优先在新生代区中分配,若没有足够空间,Minor GC;
    大对象(需要大量连续内存空间)直接进入老年态;长期存活的对象进入老年态。如果对象在新生代出生并经过第一次MGC后仍然存活,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。

    6. 你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms,g1

    这里写图片描述

    7. Eden和Survivor的比例分配等

    默认比例8:1。
    大部分对象都是朝生夕死。
    复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。
    8. 深入分析了Classloader,双亲委派机制
    ClassLoader:类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。
    双亲委派机制:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

    9. JVM的编译优化

    10. 对Java内存模型的理解,以及其在并发中的应用

    Java内存模型的主要目标: 定义程序中各个变量的访问规则。
    Java线程之间的通信由Java内存模型(本文简称为JMM)控制。
    所有变量的存储都在主内存,每条线程还都有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作必须在工作内存完成,而不能直接读取主内存中的变量。不同的线程直接无法访问对方工作内存中的变量,线程间变量的传递均需要通过主内存来完成。
    这里写图片描述

    线程间通信:
    1. 首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
    2. 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。

    11. 指令重排序,内存栅栏等

    指令重排序:编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。在单线程程序中,对存在控制依赖的操作重排序,不会改变执行结果;但在多线程程序中,对存在控制依赖的操作重排序,可能会改变程序的执行结果。

    12. OOM错误,stackoverflow错误,permgen space错误

    13. JVM常用参数

    JVM主要参数:堆设置、回收器选择(串行、并行、并发收集器)

    14. tomcat结构,类加载器流程
    这里写图片描述
    目录结构:
    • /bin:存放windows或Linux平台上启动和关闭Tomcat的脚本文件
    • /conf:存放Tomcat服务器的各种全局配置文件,其中最重要的是server.xml和web.xml
    • /doc:存放Tomcat文档
    • /server:包含三个子目录:classes、lib和webapps
    • /server/lib:存放Tomcat服务器所需的各种JAR文件
    • /server/webapps:存放Tomcat自带的两个WEB应用admin应用和 manager应用
    • /common/lib:存放Tomcat服务器以及所有web应用都可以访问的jar文件
    • /shared/lib:存放所有web应用都可以访问的jar文件(但是不能被Tomcat服务器访问)
    • /logs:存放Tomcat执行时的日志文件
    • /src:存放Tomcat的源代码
    • /webapps:Tomcat的主要Web发布目录,默认情况下把Web应用文件放于此目录
    • /work:存放JSP编译后产生的class文件

    类加载器模式,双亲委派模式:
    这里写图片描述

    15. volatile的语义,它修饰的变量一定线程安全吗

    一个变量被定义为volatile之后,具备两重语义:①保证此变量对所有线程的可见性,即当一条线程修改了这个值,新值对于其他所有线程来说是立即得知的,普通变量需要通过主内存传递。②禁止指令重排序优化。
    Volatile修饰的变量不一定是线程安全的,eg非原子操作a++等

    16. g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择

    CMS收集器:一款以获取最短回收停顿时间为目标的收集器,是基于“标记-清除”算法实现的,分为4个步骤:初始标记、并发标记、重新标记、并发清除。
    G1收集器:面向服务端应用的垃圾收集器,过程:初始标记;并发标记;最终标记;筛选回收。整体上看是“标记-整理”,局部看是“复制”,不会产生内存碎片。
    吞吐量优先的并行收集器:以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
    响应时间优先的并发收集器:保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。

    17. 说一说你对环境变量classpath的理解?如果一个类不在classpath下,为什么会抛出ClassNotFoundException异常,如果在不改变这个类路径的前期下,怎样才能正确加载这个类?

    classpath是javac编译器的一个环境变量。它的作用与import、package关键字有关。package的所在位置,就是设置CLASSPATH当编译器面对import packag这个语句时,它先会查找CLASSPATH所指定的目录,并检视子目录java/util是否存在,然后找出名称吻合的已编译文件(.class文件)。如果没有找到就会报错!
    动态加载包

    18. 说一下强引用、软引用、弱引用、虚引用以及他们之间和gc的关系

    强引用:new出的对象之类的引用,
    只要强引用还在,永远不会回收
    软引用:引用但非必须的对象,内存溢出异常之前,回收
    弱引用:非必须的对象,对象能生存到下一次垃圾收集发生之前。
    虚引用:对生存时间无影响,在垃圾回收时得到通知。

    展开全文
  • JVM常见面试题及答案

    万次阅读 多人点赞 2018-06-06 10:51:36
    11.JVM内存分哪几个区,每个区的作用是什么?java虚拟机主要分为以下一个区:方法区:1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的...

    11.JVM内存分哪几个区,每个区的作用是什么?

    java虚拟机主要分为以下一个区:

    方法区:
    1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
    2. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
    3. 该区域是被线程共享的。
    4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。

    虚拟机栈:
    1. 虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
    2. 虚拟机栈是线程私有的,它的生命周期与线程相同。
    3. 局部变量表里存储的是基本数据类型、returnAddress类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
    4.操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
    5.每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。

    本地方法栈
    本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。


    java堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。

    程序计数器
    内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域。

    12.如和判断一个对象是否存活?(或者GC对象的判定方法)

    判断一个对象是否存活有两种方法:
    1. 引用计数法
    所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一。当一个对象的引用计数器为零时,说明此对象没有被引用,也就是“死对象”,将会被垃圾回收.
    引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,那么此时A,B对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法。

    2.可达性算法(引用链法)
    该算法的思想是:从一个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何引用链相连时,则说明此对象不可用。
    在java中可以作为GC Roots的对象有以下几种:

    • 虚拟机栈中引用的对象
    • 方法区类静态属性引用的对象
    • 方法区常量池引用的对象
    • 本地方法栈JNI引用的对象

    虽然这些算法可以判定一个对象是否能被回收,但是当满足上述条件时,一个对象比不一定会被回收。当一个对象不可达GC Root时,这个对象并 
    不会立马被回收,而是出于一个死缓的阶段,若要被真正的回收需要经历两次标记
    如果对象在可达性分析中没有与GC Root的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行finalize()方法。当对象没有覆盖finalize()方法或者已被虚拟机调用过,那么就认为是没必要的。
    如果该对象有必要执行finalize()方法,那么这个对象将会放在一个称为F-Queue的对队列中,虚拟机会触发一个Finalize()线程去执行,此线程是低优先级的,并且虚拟机不会承诺一直等待它运行完,这是因为如果finalize()执行缓慢或者发生了死锁,那么就会造成F-Queue队列一直等待,造成了内存回收系统的崩溃。GC对处于F-Queue中的对象进行第二次被标记,这时,该对象将被移除”即将回收”集合,等待回收。

    13.简述java垃圾回收机制?

    在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

    14.java中垃圾收集的方法有哪些?

    1. 标记-清除:
      这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被回收的对象,然后统一回收。这种方法很简单,但是会有两个主要问题:1.效率不高,标记和清除的效率都很低;2.会产生大量不连续的内存碎片,导致以后程序在分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。
    2. 复制算法:
      为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然后一次性清楚完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。
      于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。(java堆又分为新生代和老年代)
    3. 标记-整理
      该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高时,也解决了复制算法的效率问题。它的不同之处就是在清除对象的时候现将可回收对象移动到一端,然后清除掉端边界以外的对象,这样就不会产生内存碎片了。
    4. 分代收集 
      现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代和老年代。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除

    15.java内存模型

    java内存模型(JMM)是线程间通信的控制机制.JMM定义了主内存和线程之间抽象关系。线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。Java内存模型的抽象示意图如下:

    从上图来看,线程A与线程B之间如要通信的话,必须要经历下面2个步骤:
    1. 首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
    2. 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。
    写的很好:http://www.infoq.com/cn/articles/java-memory-model-1

    16.java类加载过程?

    java类加载需要经历一下7个过程:
    加载
    加载时类加载的第一个过程,在这个阶段,将完成一下三件事情:
    1. 通过一个类的全限定名获取该类的二进制流。
    2. 将该二进制流中的静态存储结构转化为方法去运行时数据结构。 
    3. 在内存中生成该类的Class对象,作为该类的数据访问入口。

    验证
    验证的目的是为了确保Class文件的字节流中的信息不回危害到虚拟机.在该阶段主要完成以下四钟验证:
    1. 文件格式验证:验证字节流是否符合Class文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.
    2. 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。
    3. 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。
    4. 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。

    准备
    准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中。

        public static int value=123;//在准备阶段value初始值为0 。在初始化阶段才会变为123 。
    
    • 1
    • 2

    解析
    该阶段主要完成符号引用到直接引用的转换动作。解析动作并不一定在初始化动作完成之前,也有可能在初始化之后。

    初始化
    初始化时类加载的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。

    17. 简述java类加载机制?

    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的java类型。

    18. 类加载器双亲委派模型机制?

    当一个类收到了类加载请求时,不会自己先去加载这个类,而是将其委派给父类,由父类去加载,如果此时父类不能加载,反馈给子类,由子类去完成类的加载。

    19.什么是类加载器,类加载器有哪些?

    实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。
    主要有一下四种类加载器:
    1. 启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。
    2. 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
    3. 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
    4. 用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。

    20.简述java内存分配与回收策率以及Minor GC和Major GC

    1. 对象优先在堆的Eden区分配。
    2. 大对象直接进入老年代.
    3. 长期存活的对象将直接进入老年代.
      当Eden区没有足够的空间进行分配时,虚拟机会执行一次Minor GC.Minor Gc通常发生在新生代的Eden区,在这个区的对象生存期短,往往发生Gc的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。

    下一篇:java常见面试题及答案 21-30 http://blog.csdn.net/hsk256/article/details/49363271

    展开全文
  • jvm相关面试题及答案

    千次阅读 2019-07-01 16:11:52
    首先是加载阶段(Loading),它是Java将字节码数据从不同的数据源读取到JVM中,并映射为JVM认可的数据结构(Class对象),这里的数据源可能是各种各样的形态,如jar文 件、class文件,甚至是网络数据源等...
  • JVM面试题附带答案

    2020-07-09 21:32:20
    1.JVM运行时结构,各个区存放的数据 按线程可见性来分可以分为下面这两类 线程共享 堆区:堆用来存放数组和对象,内部又分为了新生代和老年代,他们的比例默认为1:2,新生代又分为了一个Eden和两个Survivor,...
  • 常见JVM面试题及答案整理

    万次阅读 多人点赞 2020-06-02 18:25:10
    总结了JVM一些经典面试题,分享出我自己的解题思路,希望对大家有帮助,有哪里你觉得不正确的话,欢迎指出,后续有空会更新。 1.什么情况下会发生栈内存溢出。 思路: 描述栈定义,再描述为什么会溢出,再说明一下...
  • 最新Java面试题,常见面试题及答案汇总

    万次阅读 多人点赞 2020-07-27 17:29:03
    Java最新面试题面试题答案汇总
  • JVM常见面试题

    千次阅读 2015-10-07 19:51:14
    写贴整理来的题目,明天再慢慢整理答案。 1. 内存模型以及分区,需要详细到每个区放什么。 2. 堆里面的分区:Eden,survival from to,老年代,各自的特点。 3. 对象创建方法,对象的内存分配,对象的访问...
  • Java架构师面试题——JVM性能调优

    万次阅读 多人点赞 2019-03-15 10:38:36
    直通BAT必考题系列:7种JVM垃圾收集器特点,优劣势、使用场景 直通BAT必考题系列:JVM的4种垃圾回收算法、垃圾回收机制与总结 直通BAT必考题系列:深入详解JVM内存模型与JVM参数详细配置 JVM内存...
  • jvm调优面试怎么答?

    千次阅读 2019-09-18 06:39:52
    一.jvm分为年轻代,年老代,持久代1.年轻代:年轻代主要存放新创建的对象,垃圾回收会比较频繁。(稍微讲细一点就是即可,年轻代分成Eden Space和Suvivor Space。当对象在堆创建时,将进入年轻代的Eden Space。垃圾...
  • 最近看书的过程中整理了一些面试题面试题以及答案都在我的文章中有所提到,希望你能在以问题为导向的过程中掌握虚拟机的核心知识。面试毕竟是面试,核心知识我们还是要掌握的,加油~~~ 下面是按jvm虚拟机知识点分...
  • 关于JVM的几道面试题

    千次阅读 2014-01-22 09:58:18
    刚刚在看书,关于虚拟机规则的,突然想到可以出如下面试题: 给出一段会产生堆内存溢出的代码;给出一段虚拟机栈和本地方法栈溢出的代码:分StackOverflowError和OutOfMemoryError给出程序;给出一段能使运行...
  • 可能是最全的java架构师面试题

    千次阅读 2019-10-10 09:14:29
    最全最新java面试题系列全家桶(带答案) 架构师职位常见面试题 源码分析 常用设计模式 23种经典设计模式都有哪些,如何分类 阿里java设计模式面试题 Spring 框架中都用到了哪些设计模式 开发中都用到了那些...
  • 一面 concurrent包下面用过哪些? countdownlatch功能实现 synchronized和lock区别,重入锁 thread和runnable的区别 AtomicInteger实现原理(CAS自旋) java并发sleep与wait、notify与notifyAll的区别 ...
  • 面试介绍 1)自我介绍? 2)项目介绍? 3)遇到的最大困难是什么?怎么解决的? 4)你觉得你能怎么优化这个项目? 面试题目 1)讲一下JVM 2)讲一下JVM的分代回收以及具体算法 3)将一下JVM的垃圾收集器,G1和CMS有...
  • 面试总问的jvm调优到底是要干什么

    万次阅读 多人点赞 2018-10-30 17:40:30
    面试总问的jvm调优到底是要干什么  请注意,jvm调优,调的是稳定,并不能带给你性能的大幅提升。服务稳定的重要性就不用多说了,保证服务的稳定,gc永远会是Java程序员需要考虑的不稳定因素之一。复杂和高并发下的...
  • JVM内存模型(面试自用)

    万次阅读 多人点赞 2019-03-07 22:31:03
    请讲一讲你对JVM内存模型的了解? 首先要说一下JVM内存空间分为五部分,分别是:方法区、堆、Java虚拟机栈、本地方法栈、程序计数器 方法区主要用来存放类信息、类的静态变量、常量、运行时常量池等,方法区的大小...
  • JVM垃圾回收算法和垃圾回收器有哪些,最新的JDK采用什么算法。 新生代和老年代的回收机制。 讲一下ArrayList和linkedlist的区别,ArrayList与HashMap的扩容方式。 Concurrenthashmap1.8后的改动。 Java中的多线程,...
  • Java面试系列:JVM与调优面试题

    万次阅读 2020-05-11 18:08:26
    一、JVM 内存区域划分 1.程序计数器(线程私有) 二、JVM 执行子系统 1.Class 类文件结构 三.垃圾回收器和内存分配策略 3.基本垃圾回收算法 四、编写高效优雅 Java 程序 1.面向对象 五、性能优化 1.常用的...
1 2 3 4 5 ... 20
收藏数 54,988
精华内容 21,995
关键字:

jvm面试题及答案