JVM、Java虚拟机

什么是java虚拟机
        可以执行 Java 字节码的虚拟机进程。java源文件被编译成能被java虚拟机执行的字节码文件。
 
java如何跨平台
        jvm会根据不用的操作系统和硬件设备,提供不同jvm。对于不同的操作系统jvm对应的质指令是不同的class文件。
 
 

Java 内存结构

       
        方法区和堆是对所有线程共享的内存区域。
        java栈,本地方法栈,程序计数器是运行线程私有的内存区域。
 

 

内存模型以及分区,需要详细到每个区放什么

    JVM 分为堆区和栈区,还有方法区,初始化的对象放在堆里面,引用放在栈里面,class 类信息常量池(static 常量和 static 变量)等放在方法区。
    方法区:存储虚拟机加载的类信息,常量,静态变量,编译后的代码等数据。
    堆:初始化的对象,成员变量(非static),所有对象的实例和数组都要在堆上分配。
    栈:由栈帧组成,调用一个方法就压入一帧。帧上面存储局部变量表,操作数栈,方法出口等信息。局部变量表存放的是8大基础类型和一个应用类型,所以还是一个指向地址的指针
    本地方法栈:主要为Native方法服务。
    程序计数器:记录当前线程执行的行号。

说一下堆栈的区别

    堆是用来存放对象的,栈是用来执行程序的。
    堆大小远远大于栈。
    堆是线程共享的,栈是线程私有的。
队列和栈是什么?有什么区别?
        队列和栈都是被用来预存储数据的。
        队列允许先进先出检索元素,但也有例外的情况,Deque 接口允许从两端检索元素。
        栈和队列很相似,但它运行对元素进行后进先出进行检索。
 

怎么判断对象是否可以被回收

        引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。
       可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。(解决循环引用的问题)。

Java 中都有哪些引用类型

    强引用:发生 gc 的时候不会被回收。
    软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
    弱引用:有用但不是必须的对象,在下一次GC时会被回收。
    虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。
 
 

 JVM 有哪些垃圾回收算法

    标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。
    标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
    复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。  
        缺点:内存使用率不高,只有原来的一半。
     分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。
 

JVM 有哪些垃圾回收器

    1.Serial:最早的单线程串行垃圾回收器。(单cpu效率最高,是Client模式的默认垃圾回收器)
    
    2.Serial Old:Serial 垃圾回收器的老年版本,同样也是单线程的,可 以作为 CMS 垃圾回收器的备选预案。
    
   3.ParNew:是 Serial 的多线程版本。  
 
    4.Parallel Scavenge和 ParNew 收集器类似是多线程的,但 Parallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量。
    
    5. Parallel Old 是 Parallel 老生代版本,Parallel 使用的是复制的内存回收算法,Parallel Old 使用的是标记-整理的内存回收算法。
    
    6.CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。
    
    7.G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。
 

 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

    新生代回收器:Serial、ParNew、Parallel Scavenge
  
    老年代回收器:Serial Old、Parallel Old、CMS
 
    整堆回收器:G1
 
    新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高。
            缺点是内存利用率低;
 
    老年代回收器一般采用的是标记-整理的算法进行垃圾回收。
 

详细介绍一下 CMS 垃圾回收器?

    
    CMS 是英文 Concurrent Mark-Sweep 的简称。
    是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。
    对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。
    在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。
    CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。
    三色标记算法:
            白色:未被标记的对象。
            灰色:自身被标记,成员变量未被标记。
            黑色:自身和成员变量均已标记完成。
 
Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互;这些现象多半是由于gc引起。
 
CMSbug解决:Incremental Update
任何垃圾回收器都有STW,降低STW时间,最好不产生。

 JVM 调优和调优的工具?

         JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。
还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具.https://blog.csdn.net/a116385895/article/details/107635628
         jconsole:用于对 JVM 中的内存、线程和类等进行监控;
         jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。
        命令:top jps jstack
            建议用 arthas
            定位问题 :jmap
            Jad反编译类
            tarce 追踪
            more         
            redefine  热更新
            案例:线程池(产生任务积压。以致于OOM)
1.监控GC的状态
使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化。
举一个例子: 系统崩溃前的一些现象:
  • 每次垃圾回收的时间越来越长,由之前的10ms延长到50ms左右,FullGC的时间也有之前的0.5s延长到4、5s
  • FullGC的次数越来越多,最频繁时隔不到1分钟就进行一次FullGC
  • 年老代的内存越来越大并且每次FullGC后年老代没有内存被释放
之后系统会无法响应新的请求,逐渐到达OutOfMemoryError的临界值,这个时候就需要分析JVM内存快照dump。
2.生成堆的dump文件
通过JMX的MBean生成当前的Heap信息,大小为一个3G(整个堆的大小)的hprof文件,如果没有启动JMX可以通过Java的jmap命令来生成该文件。
3.分析dump文件
打开这个3G的堆信息文件,显然一般的Window系统没有这么大的内存,必须借助高配置的Linux,几种工具打开该文件:
  • Visual VM
  • IBM HeapAnalyzer
  • JDK 自带的Hprof工具
  • Mat(Eclipse专门的静态内存分析工具)推荐使用
备注:文件太大,建议使用Eclipse专门的静态内存分析工具Mat打开分析。
4.分析结果,判断是否需要优化
如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化,如果GC时间超过1-3秒,或者频繁GC,则必须优化。
注:如果满足下面的指标,则一般不需要进行GC:
  • Minor GC执行时间不到50ms;
  • Minor GC执行不频繁,约10秒一次;
  • Full GC执行时间不到1s;
  • Full GC执行频率不算频繁,不低于10分钟1次;
5.调整GC类型和内存分配
如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择。
6.不断的分析和调整
通过不断的试验和试错,分析并找到最合适的参数,如果找到了最合适的参数,则将这些参数应用到所有服务器。
 

常用的 JVM 调优的参数都有哪些?

  • -Xms :s为strating,表示堆内存起始大小
  • -Xmx: x为max,表示最大的堆内存
(一般来说-Xms和-Xmx的设置为相同大小,因为当heap自动扩容时,会发生内存抖动,影响程序的稳定性)
  • -Xmn:n为new,表示新生代大小
 
-XX:SurvivorRator=8:表示堆内存中新生代、老年代和永久代的比为8:1:1
 
-XX:PretenureSizeThreshold=3145728:表示当创建(new)的对象大于3M的时候直接进入老年代
 
-XX:MaxTenuringThreshold=15:表示当对象的存活的年龄(minor gc一次加1)大于多少时,进入老年代
 
-XX:-DisableExplicirGC:表示是否(+表示是,-表示否)打开GC日志
 
 
年轻代的对象每熬过一次Minor GC,年龄就加一岁。默认15岁时,就会进入老年代。
不过这个条件并非绝对,如果Survivor中相同年龄的对象总和大于Survivor空间的一半,那么年龄大于等于该年龄的对象可以直接晋升到老年代。
 
流程:
新建的对象再新生代中,如果新生代内存不够,就进行Minor GC释放掉不活跃对象;如果还是不够,就把部分活跃对象复制到老年代中,如果还是不够,就进行MajorGC释放老年代,如果还是不够,JVM会抛出内存不足,发生oom,内存泄漏。
 
posted @ 2021-09-04 15:55  嗨,小yu  阅读(31)  评论(0)    收藏  举报