爱立信面试准备

JVM


JVM的构成

JVM 运行时内存划分

以下是JDK1.6的JVM运行时区域

JDK1.7的改变

  • 常量池和静态变量放到 Java 堆里。

JDK8 的改变

  • 字符串常量存放到堆内存中。
  • 用元空间(Metaspace) 替代了 Perm Space (废弃) ;
  • -XX:MaxMetaspaceSize :分配给类元数据空间的最大值,超过此值就会触发Full GC 。
Java对象创建过程(new A()过程)

需要注意的点:

  • 为对象分配内存
    具体的分配内存有两种情况:第一种情况是内存空间绝对规整,第二种情况是内存空间是不连续的。
    多线程并发时会出现正在给对象 A 分配内存,还没来得及修改指针,对象 B 又用这个指针分配内存,这样就出现问题了。解决这种问题有两种方案:

第一种,是采用同步的办法,使用 CAS 来保证操作的原子性。
另一种,是每个线程分配内存都在自己的空间内进行,即是每个线程都在堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB),分配内存的时候再TLAB上分配,互不干扰。可以通过 -XX:+/-UseTLAB 参数决定。

  • 为分配的内存空间初始化零值
    能保证对象即使没有赋初值,也可以直接使用。
  • 执行 init 方法
    init 方法用来执行程序中的初始化代码。
OutOfMemoryError
  • Java 堆溢出
    现象:异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。
    原因:不断创建对象,保持不被GC
    解决办法:
    通过-XX:+HeapDumpOnOutOfMemoryError得到dump文件,用镜像分析工具(如IDEA的Jprofile),重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。
    如果是内存泄露,可进一步通过工具查看泄露对象到GC Roots的引用链
    如果不存在泄露,换句话说,就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。
  • 虚拟机栈和本地方法栈溢出
    线程请求的栈深度大过大,将抛出 StackOverflowError
    如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出 OutOfMemoryError
    Hotpot 栈容量只由 -Xss参数设定 -运行时常量池溢出(仅JDK1.6)
    JDK7 将常量池和静态变量放到 Java 堆里,所以无法触发运行时常量池溢出
  • 方法区和运行时常量池溢出(仅JDK1.7及以下)
    常见原因:动态代理时,动态生成类太多,导致方法区溢出。 Java8变成元数据区的内存溢出
  • 元数据区的内存溢出
    方法区的内存溢出在 JDK8 中,变成了元数据区的内存溢出.
    常见原因:也就是JDK1.7的原因。 可通过 -XX:MaxMetaspaceSize=10m 调整
当出现了内存溢出,你怎么排错?
  1. 首先,控制台查看错误日志。
  2. 然后,使用 JDK 自带的 jvisualvm(启动可直接监控本地JVM,监控远程JVM需要配置IP) 或者用镜像分析工具jprofiler工具查看系统的堆栈日志。
  3. 定位出内存溢出的空间:堆,栈还是永久代(JDK8 以后不会出现永久代的内存溢出)。 如果是堆内存溢出,看是否创建了超大的对象。或者创建过多未回收对象(如数据库查询结果) 如果是栈内存溢出,看是否创建了超大的对象,或者产生了死循环。
垃圾收集器与内存分配策略
  • finalize的作用
    finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。建议用于:① 清理本地对象(通过JNI创建的对象);② 作为确保某些非内存资源(如Socket、文件等)释放的一个补充
  • 如何判断一个对象是否已经死去 引用计数
    每个对象有一个引用计数属性,新增一个引用时计数加 1 ,引用释放时计数减 1 ,计数为 0 时可以回收。此方法简单,无法解决对象相互循环引用的问题.
    可达性分析
    从 GC Roots 开始向下搜索,当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的.
  • Java 对象有哪些引用类型:强引用,软~,弱~,虚~
GC算法
  • 标记-清除算法
    原理:从根节点开始,标记所有可达对象,就是要回收的对象。
    缺点:效率低;产生碎片。

  • 标记-整理算法 原理:比标记清除算法多了个移动动作,将存活的对象移动到内存另一端。
    缺点:移动消耗性能。

  • 复制算法 原理:二分内存,每次只在一半内存分配空间,快用完时,移动存活对象到另一半。
    缺点:浪费空间。内存复制消耗性能。

  • 分代收集算法
    原理:将内存分新生代和老年代,采取不同算法。
    新生代:存活对象少,采用复制算法。
    老年代:存活率高,大对象多,且无额外空间,采用 标记清理,或 标记整理 算法。


上图左半部分是未回收前的内存区域,右半部分是回收后的内存区域。
对象分配策略:

优先在 Eden 区域分配,如果对象过大直接分配到 Old 区域,长时间存活的对象进入到 Old 区域

改进复制算法:
HotSpot 虚拟机默认 Eden 和 2 块 Survivor 的大小比例是 8:1:1,也就是每次新生代中可用内存空间为整个新生代容量的 90%(80%+10%),只有 10% 的内存会被“浪费”。当然,98% 的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于 10% 的对象存活,当 Survivor 空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。

JVM 垃圾收集器有哪些
新生代收集器

Serial, ParNew(Serial 的多线程版),Parallel Scavenge

老年代收集器

Serial Old(Serial 收集器的老年代版本),Parallel Old(Parallel Scavenge 收集器的老年代版本),CMS

新生代 + 老年代收集器

G1,ZGC

各种收集器对比

并行和并发

并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行。而垃圾收集程序运行在另一个CPU上。

CMS收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它非常符合那些集中在互联网站或者B/S系统的服务端上的Java应用,从名字上(“Mark Sweep”)就可以看出它是基于“标记-清除”算法实现的

G1 和 CMS 的区别
  • CMS 的缺点是对 CPU 的要求比较高。G1是将内存化成了多块,所有对内段的大小有很大的要求。
  • CMS是清除,所以会存在很多的内存碎片。G1是整理,所以碎片空间较小。
  • G1 和 CMS 都是响应优先把,他们的目的都是尽量控制 STW 时间。

如何使用指定的垃圾收集器

什么是新生代 GC 和老年代 GC

新生代GC(MinorGC/YoungGC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具备朝生夕灭的特性,所以 MinorGC 非常频繁,一般回收速度也比较快。
老年代GC(MajorGC/FullGC):指发生在老年代的 GC,出现了 MajorGC,经常会伴随至少一次的 MinorGC(但非绝对的,在 Parallel Scavenge 收集器的收集策略里就有直接进行 MajorGC 的策略选择过程)。MajorGC 的速度一般会比 MinorGC 慢 10 倍以上。

什么情况下会出现 Young GC

对象优先在新生代 Eden 区中分配,如果 Eden 区没有足够的空间时,就会触发一次 Young GC

什么情况下回出现 Full GC

Full GC 的触发条件有多个,FULL GC 的时候会 STOP THE WORD 。

  • 在执行 Young GC 之前,JVM 会进行空间分配担保——如果老年代的连续空间小于新生代对象的总大小(或历次晋升的平均大小),则触发一次 Full GC 。
  • 大对象直接进入老年代,从年轻代晋升上来的老对象,尝试在老年代分配内存时,但是老年代内存空间不够。
  • 显式调用 System#gc() 方法时。
JDK 的可视化工具有哪些可以监控虚拟机

JConsole(JDK自带) :Java 监视与管理控制台,监控JVM 中内存,线程和类。 JVisualVM(JDK自带的故障处理工具):,可以分析内存快照、线程快照、监控内存变化、GC变化等。 JProfiler(第三方),分析快照。

调优案例分析与实战

https://blog.csdn.net/zhaojw_420/article/details/70527138

类加载机制:什么是双亲委派模型(Parent Delegation Model)
为什么优先使用父 ClassLoader 加载类?
  • 共享功能:可以避免重复加载,当父亲已经加载了该类的时候,子类不需要再次加载,一些 Framework 层级的类一旦被顶层的 ClassLoader 加载过就缓存在内存里面,以后任何地方用到都不需要重新加载。
  • 隔离功能:主要是为了安全性,避免用户自己编写的类动态替换 Java 的一些核心类,比如 String ,同时也避免了重复加载,因为 JVM 中区分不同类,不仅仅是根据类名,相同的 class 文件被不同的 ClassLoader 加载就是不同的两个类,如果相互转型的话会抛 java.lang.ClassCaseException 。(或者问String类是否能被重写?)
什么是破坏双亲委托模型?(怎样自定义一个String类)

破坏双亲委托模型,需要做的是,#loadClass(String name, boolean resolve) 方法中,不调用父 parent ClassLoader 方法去加载类,那么就成功了。那么我们要做的仅仅是,错误的覆盖 ##loadClass(String name, boolean resolve) 方法,不去使用父 parent ClassLoader 方法去加载类即可。

MYSQL


InnoDB 和 MyISAM 的区别
  • 事务
  • 行锁
  • 索引方式
MySQL 索引的“创建”原则 MySQL 索引的“创建”原则
  • 最适合索引的列是出现在 WHERE 子句中的列
  • 索引列的基数越大,索引效果越好-避免不走索引
  • 复合索引可以提高查询效率-因为复合索引的基数会更大
  • 避免创建过多的索引
  • 主键尽可能选择较短的数据类型,最好带自然排序类型
MySQL 索引的“使用”注意事项
  • 应尽量避免在 WHERE 子句中使用 != 或 <>, OR
  • 尽量避免在 WHERE 子句中对字段进行表达式/函数操作
  • 不要在 WHERE 子句中的 = 左边进行函数、算术运算或其他表达式运算
  • 复合索引遵循前缀原则
  • LIKE 查询,% 不能在前
MySQL 索引的原理
什么是 B-Tree 索引

B-Tree 是为磁盘等外存储设备设计的一种平衡查找树。
非叶子结点的key都是[key,data]二元组,其中key表示作为索引的键,data为键值所在行的数据
在BTree的机构下,就可以使用二分查找的查找方式,查找复杂度为h*log(n)

B+Tree索引

B+Tree是BTree的一个变种,主要区别为:

  • B+Tree中的非叶子结点不存储数据,只存储键值
  • B+Tree的叶子结点没有指针,所有键值都会出现在叶子结点上,且key存储的键值对应data数据的物理地址
  • B+Tree的每个非叶子节点由n个键值key和n个指针point组成
B+Tree对比BTree的优点

操作系统一页(page)通常默认为4K,数据库的页通常设置为操作系统页的整数倍,因此索引结构的节点被设计为一个页的大小,然后利用外存的“预读取”原则,每次读取的时候,把整个节点的数据读取到内存中,然后在内存中查找,每个节点中的key个数越多,那么树的高度越小,需要I/O的次数越少,因此一般来说B+Tree比BTree更快,因为B+Tree的非叶节点中不存储data,就可以存储更多的key。
原文:https://blog.csdn.net/tongdanping/article/details/79878302

聚簇索引和非聚簇索引
MyISAM——非聚簇索引
  • 非聚簇索引的主索引和辅助索引几乎是一样的,只是主索引不允许重复,不允许空值,他们的叶子结点的key都存储指向键值对应的数据的物理地址
  • 非聚簇索引的数据表和索引表是分开存储的。

既然非聚簇索引的主索引和辅助索引指向相同的内容,为什么还要辅助索引呢?如果查询的条件不是主键怎么办呢,这个时候就需要辅助索引了

InnoDB——聚簇索引

  • 聚簇索引的主索引的叶子结点存储的是键值对应的数据行本身,辅助索引的叶子结点存储的是键值对应的数据的主键键值因此主键的值长度越小越好,类型越简单越好。
  • 聚簇索引的数据是根据主键的顺序保存。因此适合按主键索引的区间查找,可以有更少的磁盘I/O,加快查询速度。但是也是因为这个原因,聚簇索引的插入顺序最好按照主键单调的顺序插入,否则会频繁的引起页分裂(平衡树旋转),严重影响性能
MySQL 的四种事务隔离级别

事务的特性指:原子性(都成功都失败),一致性(符合约束),隔离性(并发),持久性

事务的并发问题
  • 脏读:事务 A 读取了事务 B 更新的数据,然后 B 回滚操作,那么 A 读取到的数据是脏数据。
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据作了更新并提交,导致事务 A 多次读取同一数据时,结果不一致。
  • 幻读:系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
MySQL 事务隔离级别会产生的并发问题
  • READ UNCOMMITTED - 导致脏读
  • READ COMMITTED - 导致不可重读
  • REPEATABLE READ - 导致幻读

MySQL 中 InnoDB 引擎的行锁是通过加在什么上完成(或称实现)的?为什么是这样子的??

Dubbo


整体

dubbo是默认推荐的方式,使用长连接,nio的形式。实现上就是服务消费方与服务提供方及注册中心之间使用单一长连接,NIO

使用默认dubbo协议的话,序列化使用的是修改过的hessian协议,这是一种高效的二进制与具体语言无关的协议。而服务提供者端与服务消费者端使用的是mina nio框架

配置
<dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。
eg、<dubbo:service ref="demoService" interface="com.unj.dubbotest.provider.DemoService" />

<dubbo:reference/> 引用服务配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。
eg、<dubbo:reference id="demoService" interface="com.unj.dubbotest.provider.DemoService" />

<dubbo:protocol/> 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
eg、<dubbo:protocol name="dubbo" port="20880" />

<dubbo:application/> 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。
eg、<dubbo:application name="xixi_provider" />
    <dubbo:application name="hehe_consumer" />

<dubbo:module/> 模块配置,用于配置当前模块信息,可选。
<dubbo:registry/> 注册中心配置,用于配置连接注册中心相关信息。
eg、<dubbo:registry address="zookeeper://192.168.2.249:2181" />

<dubbo:monitor/> 监控中心配置,用于配置连接监控中心相关信息,可选。
<dubbo:provider/> 提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:consumer/> 消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:method/> 方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息。
<dubbo:argument/> 用于指定方法参数配置。
Dubbo 调用是同步的吗?

默认情况下,调用是同步的方式。

Dubbo 的异常处理机制

1)如果provider实现了GenericService接口,直接抛出

2)如果是checked异常,直接抛出

3)在方法签名上有声明,直接抛出

4)异常类和接口类在同一jar包里,直接抛出

5)是JDK自带的异常,直接抛出

6)是Dubbo本身的异常,直接抛出

7)否则,包装成RuntimeException抛给客户端

网上有些文章对7)的处理有疑问,不理解原因,其实就是为了防止客户端反序列化失败.前面几种情况都能保证反序列化正常.

Dubbo 可以对调用结果进行缓存吗?

Dubbo 通过 CacheFilter 过滤器,提供结果缓存的功能

Dubbo 目前提供三种实现:

lru :基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。 threadlocal :当前线程缓存,比如一个页面渲染,用到很多 portal,每个 portal 都要去查用户信息,通过线程缓存,可以减少这种多余访问。 jcache :与 JSR107 集成,可以桥接各种缓存实现。

注册中心挂了还可以通信吗?

可以。对于正在运行的 Consumer 调用 Provider 是不需要经过注册中心,所以不受影响。并且,Consumer 进程中,内存已经缓存了 Provider 列表

那么,此时 Provider 如果下线呢?如果 Provider 是正常关闭,它会主动且直接对和其处于连接中的 Consumer 们,发送一条“我要关闭”了的消息。那么,Consumer 们就不会调用该 Provider ,而调用其它的 Provider 。

如果 Consumer 重启,依然能够通过本地缓存的文件,获得到 Provider 列表。

Dubbo 在 Zookeeper 存储了哪些信息?

provider和consumer分别写入自己的URL

Dubbo Consumer 只能调用从注册中心获取的 Provider 么?

在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连。

<dubbo:reference id="xxxService"interface="com.alibaba.xxx.XxxService"url="dubbo://localhost:20890"/>

或者启动时 java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890

dubbo通信协议之对比

https://blog.csdn.net/u012546203/article/details/72149050

什么是本地暴露和远程暴露

本地调用使用了 injvm:// 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链.

举个例子,Spring Boot Controller 调用 Service 逻辑,就变成了调用 Dubbo Service Proxy 对象。这样,如果未来有一天,本地 Dubbo Service 迁移成远程的 Dubbo Service ,只需要进行配置的修改,而对 Controller 是透明的

Dubbo 支持哪些序列化方式?

【重要】Hessian2 :基于 Hessian 实现的序列化拓展。dubbo:// 协议的默认序列化方案。

Dubbo 自己实现的序列化拓展。

Dubbo 有哪些负载均衡策略
  • Random LoadBalance(默认):按权重设置随机概率。
  • RoundRobin LoadBalance:按公约后的权重设置轮询比率,存在慢的提供者累积请求的问题。
  • LeastActive LoadBalance:最少活跃调用数,使慢的提供者收到更少请求
  • ConsistentHash LoadBalance:一致性 Hash,相同参数的请求总是发到同一提供者,当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
Dubbo 六种集群容错策略
  • Failover Cluster:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
  • Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录
  • Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
  • Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
  • Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
  • Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
dubbo服务注册过程
group和version

当一个接口有多种实现时,可以用group区分。
为什么要用dubbo分组配置?
因为服务器有限,想在同一个注册中心中,分隔测试和开发环境。
当一个接口的实现,出现不兼容升级时,可以用版本号过渡

一常见问题:

1、Dubbo调用接口,该接口抛出的运行时异常,在调用函数里面无法捕获的.
2、一个经典问题: Forbid consumer 127.0.0.1 access service com.mall.api.service.MallService from registry localhost:2181 use dubbo version 2.9.2-SNAPSHOT, Please check registry access list (whitelist/blacklist).
这个错误一般表面上说禁止消费服务,实际上开发人员并没有做任何限制。其实,这个问题一般由两种情况引起的
(1)第一种情况:没有provider提供对应的服务
(2)第二种情况:消费者消费的服务的“版本号 version”和生产者提供的服务的“版本号 version”不一致,或者没有显式说明版本号。
3、当dubbo超时,返回的结果会为null
4、dubbo如果报异常了,dubbo不会返回错误码,因此需要在对外提供的接口处利用参数传递错误码、错误信息
5、在dubbo的provider和consumer的配置文件中,如果都配置了timeout的超时时间,dubbo默认以consumer中配置的时间为准

原文:https://blog.csdn.net/yellowfarf/article/details/82948427

转载于:https://my.oschina.net/u/3300976/blog/3035793

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值