zoukankan      html  css  js  c++  java
  • JAVA面试:第一章JVM


    jdk的垃圾回收算法,年轻代,老年代分别是什么

    • 垃圾回收基础算法
    1. 标记清除(mark sweep) - 位置不连续 产生碎片 效率偏低(两遍扫描)

      • 第一遍扫描找到有用的,第二遍找到没用的进行清除

    2. 拷贝算法 (copying) - 没有碎片,浪费空间,移动复制对象需要调整对象引用

      • 把一块内存中有用的对象 复制到一块干净的内存中,然后把上面无用垃圾清除

    3. 标记压缩(mark compact) - 没有碎片,效率偏低(两遍扫描,指针需要调整)

      • 标记后进行压缩,移动对象指针引用需要调整

    • 以下为分代模型的垃圾回收算法

    • 年轻代:

      • Serial 串行回收
      • PS 并行回收
      • ParNew 配合CMS的并行回收
    • 老年代:

      • SerialOld 串行回收
      • ParallelOld 并行回收
      • ConcurrentMarkSweep 老年代 并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)
        CMS问题比较多,所以现在没有一个版本默认是CMS,只能手工指定
        CMS既然是MarkSweep,就一定会有碎片化的问题,碎片到达一定程度,CMS的老年代分配对象分配不下的时候,使用SerialOld 进行老年代回收
    • 除Epsilon ZGC Shenandoah之外的GC都是使用逻辑分代模型

    • G1是逻辑分代,物理不分代

    • 除此之外的不仅逻辑分代,而且物理分代

    • G1(10ms)

      • 算法:三色标记 + SATB (SATB保证了在并发标记过程中新分配对象不会漏标)

    • ZGC (1ms)

      • 算法:ColoredPointers + LoadBarrier

    • Shenandoah

      • 算法:ColoredPointers + WriteBarrier

    • 1.8默认的垃圾回收:PS + ParallelOld

    如何排查生产环境的OOM

    • 首先确保对OOM日志的保存

    • jinfo pid

      进程和线程的 具体信息

    • jstack

      jstack 定位线程、进程状况

    • jmap -histo pid | head -20

      查找产生对象数 排名前20 的对象具体是哪些

    • jmap -dump:live,format=b,file=heap.bin pid

      生成dump转储文件,线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿(电商不适合)

    • 使用MAT / jhat /jvisualvm 进行dump文件分析
      https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html

    • jhat -J-mx512M xxx.dump

    分析日志很重要

    dump 文件里,值得关注的线程状态有:

    • 死锁,Deadlock(重点关注)

    • 执行中,Runnable

    • 等待资源,Waiting on condition(重点关注)

    • 等待获取监视器,Waiting on monitor entry(重点关注)

    • 暂停,Suspended

    • 对象等待中,Object.wait() 或 TIMED_WAITING

    • 阻塞,Blocked(重点关注)

    • 停止,Parked

      tid指Java Thread id。nid指native线程的id。prio是线程优先级。

      [0x00007f1d2c4be000] 是线程栈起始地址。

      Thread.State:WAITING (parking) 等待,线程挂起中。

      parking to wait for <0x00000000f5dee038>

      本线程肯定是在等待某个条件的发生,来把自己唤醒。其次,SynchronousQueue 并不是一个队列,只是线程之间移交信息的机制,当我们把一个元素放入到 SynchronousQueue 中时必须有另一个线程正在等待接受移交的任务,因此这就是本线程在等待的条件。

    dump文件实例分析

    https://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html

    jconsole远程连接

    https://blog.csdn.net/wangnanwlw/article/details/102381882

    1. 程序启动加入参数:

      java -Djava.rmi.server.hostname=192.168.17.11 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar test.jar 
      
    2. 如果遭遇 Local host name unknown:错误,修改/etc/hosts文件,把ip加入进去

      192.168.17.11 basic localhost localhost.localdomain localhost4 localhost4.localdomain4
      ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
      
    3. 关闭linux防火墙(实战中应该打开对应端口)

      service iptables stop
      chkconfig iptables off #永久关闭
      
    4. windows上打开 jconsole远程连接 192.168.17.11:11111

    jvisualvm远程连接

    https://www.cnblogs.com/liugh/p/7620336.html (简单做法)

    jprofiler (收费)

    arthas在线排查工具

    • 为什么需要在线排查?
      在生产上我们经常会碰到一些不好排查的问题,例如线程安全问题,用最简单的threaddump或者heapdump不好查到问题原因。为了排查这些问题,有时我们会临时加一些日志,比如在一些关键的函数里打印出入参,然后重新打包发布,如果打了日志还是没找到问题,继续加日志,重新打包发布。对于上线流程复杂而且审核比较严的公司,从改代码到上线需要层层的流转,会大大影响问题排查的进度。
    • jvm观察jvm信息
    • thread定位线程问题
    • dashboard 观察系统情况
    • heapdump + jhat分析
    • jad反编译
      动态代理生成类的问题定位
      第三方的类(观察代码)
      版本问题(确定自己最新提交的版本是不是被使用)
    • redefine 热替换
      目前有些限制条件:只能改方法实现(方法已经运行完成),不能改方法名, 不能改属性
      m() -> mm()
    • sc - search class
    • watch - watch method
    • 没有包含的功能:jmap

    jvm的内存模型

    • Java Memory Model

    • 一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范。

    • jmm是jvm的一种规范,定义了jvm的内存模型。它屏蔽了各种硬件和操作系统的访问差异,不像c那样直接访问硬件内存,相对安全很多,它的主要目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。可以保证并发编程场景中的原子性、可见性和有序性。
      链接:https://www.jianshu.com/p/76959115d486

    • 根据JVM虚拟机规范,管理内存如下

    PC 程序计数器 (独享)

    存放指令位置

    虚拟机的运行,类似于这样的循环:

    while( not end ) {

    ​ 取PC中的位置,找到对应位置的指令;

    ​ 执行该指令;

    ​ PC ++;

    }

    JVM Stack 、Frame (独享)

    • 栈帧(Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接

      (Dynamic Linking)、方法返回值和异常分派

    • 栈帧随着方法调用而创建,随着方法结束而销毁

    • 栈帧的存储空间分配在 Java 虚拟机栈之中,每一个栈帧都有自己的局部变量表(Local Variables)、操作数栈(OperandStack)和指向当前方法所属的类的运行时常量池的引用。

    1. Frame - 每个方法对应一个栈帧
      1. Local Variable Table
      2. Operand Stack
        对于long的处理(store and load),多数虚拟机的实现都是原子的
        jls 17.7,没必要加volatile
      3. Dynamic Linking
        https://blog.csdn.net/qq_41813060/article/details/88379473
        jvms 2.6.3
      4. return address
        a() -> b(),方法a调用了方法b, b方法的返回值放在什么地方

    Heap (共享)

    • 在 Java 虚拟机中,堆(Heap)是可供各条线程共享的运行时内存区域,也是供所有类实例
      和数组对象分配内存的区域。
    • Java 堆在虚拟机启动的时候就被创建,它存储了被自动内存管理系统,也即是常说的“Garbage Collector(垃圾收集器)”)所管理的各种
      对象,这些受管理的对象无需,也无法显式地被销毁。

    Method Area (共享)

    1. Perm Space (<1.8)
      字符串常量位于PermSpace永久区
      FGC不会清理
      大小启动的时候指定,不能变

    2. Meta Space (>=1.8)
      字符串常量位于堆
      会触发FGC清理
      不设定的话,最大就是物理内存

      它存储了每一个类的结构信息,例如运行时常量池(Runtime Constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法

    Runtime Constant Pool

    • 每一个运行时常量池都分配在 Java 虚拟机的方法区之中
    • 在类和接口被加载到虚拟机后,对应的运行时常量池就被创建出来。

    Native Method Stack

    • JVM实现使用到传统的栈(通常称之为“C Stacks”)来支持 native 方法(指使用 Java 以外的其他语言编写的方法)的执行,这个栈就是本地方法栈,一般会在线程创建的时候按线程分配。
    • 当 Java 虚拟机使用其他语言(例如 C 语言)来实现指令集解释器时,也会使用到本地方法栈。

    Direct Memory

    JVM可以直接访问的内核空间的内存 (OS 管理的内存)

    NIO , 提高效率,实现zero copy


    java如何加载类的,哪种情况下不需要用java的双亲委派模型来加载类(java的类加载原理)

    双亲委派的打破

    1. 如何打破:重写loadClass()
    2. 何时打破过?
      1. JDK1.2之前,自定义ClassLoader都必须重写loadClass()
      2. ThreadContextClassLoader可以实现基础类调用实现类代码,通过thread.setContextClassLoader指定
      3. 热启动,热部署
        1. osgi tomcat 都有自己的模块指定classloader(可以加载同一类库的不同版本)

    hashMap的原理,1.7和1.8的区别是什么,如何保证并发安全

    • JDK7 数组+链表
    • JDK8 数组+链表+红黑树 链表长度大于等于8 红黑树 小于等于6 链表
    • new HashMap() 时初始容量是0
    • put()的时候 开辟空间

    HashMap在jdk1.8之后引入了红黑树的概念,表示若桶中链表元素超过8时,会自动转化成红黑树;

    若桶中元素小于等于6时,树结构还原成链表形式。

    原因:

    • 链表的时间复杂度是O(n),红黑树的时间复杂度O(logn),很显然,红黑树的复杂度是优于链表的
    • 红黑树的平均查找长度是log(n),长度为8,查找长度为log(8)=3,
    • 链表的平均查找长度为n/2,当长度为8时,平均查找长度为8/2=4,
    • 其实在大于5时,红黑树已经优于链表的 平均查找长度
    • 树节点所占空间是普通节点的两倍,所以只有当节点足够多的时候,才会使用树节点。
    • 也就是说,节点少的时候,尽管时间复杂度上,红黑树比链表好一点,但是红黑树所占空间比较大,综合考虑,认为只能在节点太多的时候,红黑树占空间大这一劣势不太明显的时候,才会舍弃链表,使用红黑树。

    选择6和8的原因是:

    • 中间有个差值7可以防止链表和树之间频繁的转换。
    • 假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低。

    如何保证并发安全

    • 多线程下使用HashMap会出现了死循环和丢失数据,导致部分线程一直运行,占用cpu时间。
      • 问题原因就是HashMap是非线程安全的,多个线程put的时候造成了某个key值Entry key List的死循环,问题就这么产生了。
        当另外一个线程get 这个Entry List 死循环的key的时候,这个get也会一直执行。最后结果是越来越多的线程死循环,最后导致服务器宕机
    • 方法上加Synchronized或者方法内部map执行操作时进行加锁
    • 强烈建议使用concurrentHashMap解决多线程并发问题

    concurrentHashMap的并发原理,1.7和1.8的区别是什么

    https://www.jianshu.com/p/e694f1e868ec

  • 相关阅读:
    Java -- 基于JDK1.8的LinkedList源码分析
    Java -- 基于JDK1.8的ArrayList源码分析
    Android -- AsyncTask源码解析
    Android -- 自定义view实现keep欢迎页倒计时效果
    Android -- 《 最美有物》好看的点赞效果
    Android -- Glide框架详解(一)
    Android -- 从源码解析Handle+Looper+MessageQueue机制
    面试 -- 关于Activity的相关知识
    用最简单的一个例子看maven冲突的解决办法
    【跟我一起读 linux 源码 01】boot
  • 原文地址:https://www.cnblogs.com/JMrLi/p/13918032.html
Copyright © 2011-2022 走看看