精华内容
下载资源
问答
  • 最新全JVM优化面试热点分析.zip
  • JVM优化面试热点分析
  • jvm--Java堆、方法区、Java虚拟机栈、本地方法栈、程序计数器 程序计数器(Program Counter Register) 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器。 每一条JVM线程都有...

    目录

    一、JVM内存模型

    1、程序计数器(Program Counter Register)

    2、Java虚拟机栈(Java Virtual Machine Stack)

    3、本地方法栈(Native Method Stack)

    4、Java堆(Java Heap)

    5、运行时常量池(Runtime Constant Pool)

    6、直接内存(Direct Memory)

    7、方法区(Method Area)

    二、内存常见问题

    1、共享内存区划分

    2、常见参数的配置

    堆栈相关

    垃圾收集器参数

    怎么打出线程栈信息。

    堆栈日志信息分析

    3、JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代

    4、几种垃圾收集器:

    jdk1.7或1.8 默认垃圾收集器

    5、CMS收集器和G1收集器的区别

    6、FullGC

    7、GC roots

    8、GC Roots对象

    9、什么原因导致了连续的FullGC?

    10、如何来解决连续的FullGC?

    1.增加JVM的堆内存

    2.增加Perm或者Metaspace内存

    3.增加更多的JVM实例

    11、JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存。

    12、java内存模型中堆和栈的区别

    13、指令重排

    14、内存屏障


     

     

    一、JVM内存模型

    jvm--Java堆、方法区、Java虚拟机栈、本地方法栈、程序计数器

     

    1、程序计数器(Program Counter Register)

     

    它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器。

    每一条JVM线程都有自己的PC寄存器,各条线程之间互不影响,独立存储,这类内存区域被称为“线程私有”内存

    在任意时刻,一条JVM线程只会执行一个方法的代码。该方法称为该线程的当前方法(Current Method)

    如果该方法是java方法,那PC寄存器保存JVM正在执行的字节码指令的地址

    如果该方法是native,那PC寄存器的值是undefined。

    此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

     

    2、Java虚拟机栈(Java Virtual Machine Stack)

     

    与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。

    虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

    每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

    JVM stack 可以被实现成固定大小,也可以根据计算动态扩展。

    如果采用固定大小的JVM stack设计,那么每一条线程的JVM Stack容量应该在线程创建时独立地选定。JVM实现应该提供调节JVM Stack初始容量的手段;

    如果采用动态扩展和收缩的JVM Stack方式,应该提供调节最大、最小容量的手段。

    如果线程请求的栈深度大于虚拟机所允许的深度将抛出StackOverflowError;

    如果JVM Stack可以动态扩展,但是在尝试扩展时无法申请到足够的内存时抛出OutOfMemoryError。

     

    3、本地方法栈(Native Method Stack)

     

    本地方法栈与虚拟机栈作用相似,后者为虚拟机执行Java方法服务,而前者为虚拟机用到的Native方法服务。

    虚拟机规范对于本地方法栈中方法使用的语言,使用方式和数据结构没有强制规定,甚至有的虚拟机(比如HotSpot)直接把二者合二为一。

    这玩意儿抛出的异常跟上面的虚拟机栈一样。

     

    4、Java堆(Java Heap)

     

    虚拟机管理的内存中最大的一块,同时也是被所有线程所共享的,它在虚拟机启动时创建,这货存在的意义就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。

    这里面的对象被自动管理,也就是俗称的GC(Garbage Collector)所管理。用就是了,有GC扛着呢,不用操心销毁回收的事儿。

    Java堆的容量可以是固定大小,也可以随着需求动态扩展(-Xms和-Xmx),并在不需要过多空间时自动收缩。

    Java堆所使用的内存不需要保证是物理连续的,只要逻辑上是连续的即可。

    JVM实现应当提供给程序员调节Java 堆初始容量的手段,对于可动态扩展和收缩的堆来说,则应当提供调节其最大和最小容量的手段。

    如果堆中没有内存完成实例分配并且堆也无法扩展,就会抛OutOfMemoryError。

    这里有一个小例子,来说明堆,栈和方法区之间的关系的

    public class Test2 {
    
    	public static void main(String[] args) {
    
    		public Test2 t2 = new Test2();
    
    		//JVM将Test2类信息加载到方法区,new Test2()实例保存在堆区,Test2引用保存在栈区  
    
    		}
    }

     

    5、运行时常量池(Runtime Constant Pool)

     

    它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,

    这部分内容将在类加载后存放到方法区的运行时常量池中。

    Java虚拟机对Class文件的每一部分(自然也包括常量池)的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范上的要求,这样才会被虚拟机认可、装载和执行。但对于运行时常量池,

    Java虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。

    不过,一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。

    运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,

    运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。

    既然运行时常量池是方法区的一部分,自然会受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

     

    6、直接内存(Direct Memory)

     

    直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。

    JDK1.4加的NIO中,ByteBuffer有个方法是allocateDirect(int capacity) ,这是一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,

    然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

    显然,本机直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM及SWAP区或者分页文件)的大小及处理器寻址空间的限制。

    服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),

    从而导致动态扩展时出现OutOfMemoryError异常。

     

    7、方法区(Method Area)

     

    跟堆一样是被各个线程共享的内存区域,用于存储以被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然这个区域被虚拟机规范把方法区描述为堆的一个逻辑部分,

    但是它的别名叫非堆,用来与堆做一下区别。

    方法区在虚拟机启动的时候创建。

    方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。

    方法区在实际内存空间中可以是不连续的。

    Java虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段,对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段。

    当方法区无法满足内存分配需求时就会抛OutOfMemoryError。

     

    二、内存常见问题

     

    1、共享内存区划分

    共享内存区 = 持久带 + 堆

    持久带 = 方法区 + 其他

    Java堆 = 老年代 + 新生代

    新生代 = Eden + S0 + S1

     

    默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ,可以通过参数 –XX:NewRatio 配置。

    默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定)

    Survivor区中的对象被复制次数为15(对应虚拟机参数 -XX:+MaxTenuringThreshold)

    为什么要分为Eden和Survivor?为什么要设置两个Survivor区?

    如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC.老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多,所以需要分为Eden和Survivor。

    Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。

    设置两个Survivor区最大的好处就是解决了碎片化,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)

    2、常见参数的配置

    堆栈相关

    -Xmx3550m: 最大堆大小为3550m。

    -Xms3550m: 设置初始堆大小为3550m。

    -Xmn2g: 设置年轻代大小为2g。

    -Xss128k: 每个线程的大小为128k。

    -XX:MaxPermSize: 设置持久代大小为16m

    -XX:NewRatio=4: 设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。

    -XX:SurvivorRatio=4: 设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

    -XX:MaxTenuringThreshold=0: 设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。

    垃圾收集器参数

    -XX:+UseParallelGC: 选择垃圾收集器为并行收集器。

    -XX:ParallelGCThreads=20: 配置并行收集器的线程数

    -XX:+UseConcMarkSweepGC: 设置年老代为并发收集。

    -XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。

    -XX:+UseCMSCompactAtFullCollection: 打开对年老代的压缩。可能会影响性能,但是可以消除碎片

     

    怎么打出线程栈信息。

    思路: 可以说一下jps,top ,jstack这几个命令,再配合一次排查线上问题进行解答。

    我的答案:

    输入jps,获得进程号。

    top -Hp pid 获取本进程中所有线程的CPU耗时性能

    jstack pid命令查看当前java进程的堆栈状态

    或者 jstack -l > /tmp/output.txt 把堆栈信息打到一个txt文件。

    可以使用fastthread 堆栈定位,fastthread.io/

    例如:

    1、jps:查看本地正在运行的java进程和进程ID(pid)

    2、jinfo pid,查看指定pid的所有JVM信息

      1)jinfo -flags pid 查询虚拟机运行参数信息。

      2)jinfo -flag name pid,查询具体参数信息,如jinfo -flag UseSerialGC 42324,查看是否启用UseSerialGC

     

    3、jmap

      1)jmap -heap pid:输出堆内存设置和使用情况(JDK11使用jhsdb jmap --heap --pid pid)

      2)jmap -histo pid:输出heap的直方图,包括类名,对象数量,对象占用大小

      3)jmap -histo:live pid:同上,只输出存活对象信息

      4)jmap -clstats pid:输出加载类信息

      5)jmap -help:jmap命令帮助信息

    4、jstat:Java虚拟机统计工具,全称“Java Virtual Machine statistics monitoring tool”。可以用于监视JVM各种堆和非堆内存大小和使用量

      1)jstat -class pid:输出加载类的数量及所占空间信息。

      2)jstat -gc pid:输出gc信息,包括gc次数和时间,内存使用状况(可带时间和显示条目参数)

      其他命令不一一列举。

     

    堆栈日志信息分析

    -XX:+PrintGC 输出形式:

    [GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]

    -XX:+PrintGCDetails 输出形式:

    [GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs

     

    YoungGC:

     

    FullGC:

     

     

     

    3、JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代

    思路: 先描述一下Java堆内存划分,再解释Minor GC,Major GC,full GC,描述它们之间转化流程。

    我的答案:

    Java堆 = 老年代 + 新生代

    新生代 = Eden + S0 + S1

    当 Eden 区的空间满了, Java虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象,则会转移到 Survivor区。

    大对象(需要大量连续内存空间的Java对象,如那种很长的字符串)直接进入老年态;

    如果对象在Eden出生,并经过第一次Minor GC后仍然存活,并且被Survivor容纳的话,年龄设为1,每熬过一次Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长期存活的对象进入老年态。

    老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行Full GC,Full GC 清理整个内存堆 – 包括年轻代和年老代。

    Major GC 发生在老年代的GC,清理老年区,经常会伴随至少一次Minor GC,比Minor GC慢10倍以上。

    5.你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,包括原理,流程,优缺点。

    思路: 一定要记住典型的垃圾收集器,尤其cms和G1,它们的原理与区别,涉及的垃圾回收算法。

    我的答案:

     

    4、几种垃圾收集器:

     

    Serial收集器: 单线程的收集器,收集垃圾时,必须stop the world,使用复制算法。

    ParNew收集器: Serial收集器的多线程版本,也需要stop the world,复制算法。

    Parallel [ˈpærəlel] Scavenge [ˈskævɪndʒ] 收集器: 新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞吐量。如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%。

    Serial Old收集器: 是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。

    Parallel Old收集器: 是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法。

    CMS(Concurrent Mark Sweep) 收集器: 是一种以获得最短回收停顿时间为目标的收集器,标记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎片。

    G1收集器: 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选标记。不会产生空间碎片,可以精确地控制停顿。

     

    jdk1.7或1.8 默认垃圾收集器

    使用参数打印日志
    java -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -version  或者  java -XX:+PrintFlagsFinal
    结论:
    1.8或1.7默认的是 UseParallelGC
    ParallelGC 默认的是 Parallel Scavenge(新生代)+ Parallel Old(老年代)
    在JVM中是+XX配置实现的搭配组合:
    UseSerialGC 表示 “Serial” + "Serial Old"组合
    UseParNewGC 表示 “ParNew” + “Serial Old”
    UseConcMarkSweepGC 表示 “ParNew” + “CMS”. 组合,“CMS” 是针对旧生代使用最多的
    UseParallelGC 表示 “Parallel Scavenge” + "Parallel Old"组合
    UseParallelOldGC 表示 “Parallel Scavenge” + "Parallel Old"组合
    在实践中使用UseConcMarkSweepGC 表示 “ParNew” + “CMS” 的组合是经常使用的

     

    5、CMS收集器和G1收集器的区别

    CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用;

    G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;

    CMS收集器以最小的停顿时间为目标的收集器;

    G1收集器可预测垃圾回收的停顿时间

    CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片

    G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片

     

    6、FullGC

    1.CPU利用率飙升

    2.由于应用暂停导致应用的响应时间变长,这会影响服务的可用性和用户体验。

     

    7、GC roots

    GC管理的主要区域是Java堆,一般情况下只针对堆进行垃圾回收。方法区、栈和本地方法区不被GC所管理,因而选择这些区域内的对象作为GC roots,被GC roots引用的对象不被GC回收。

    常说的GC(Garbage Collector) roots,特指的是垃圾收集器(Garbage Collector)的对象,GC会收集那些不是GC roots且没有被GC roots引用的对象。

    一个对象可以属于多个root,GC root有几下种:

    Class - 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots。

    Thread - 活着的线程

    Stack Local - Java方法的local变量或参数

    JNI Local - JNI方法的local变量或参数

    JNI Global - 全局JNI引用

    Monitor Used - 用于同步的监控对象

    Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并没有为这些对象提供其它的信息,因此需要去确定哪些是属于"JVM持有"的了。

     

    8、GC Roots对象

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

     

    9、什么原因导致了连续的FullGC?

    导致连续的FullGC主要只有一个原因:JVM的堆内存不够用或者是Perm、Metaspace内存不够用,说明应用需要比你分配的内存更多的内存。通俗地说就是小马拉大车。

    所以JVM必须要努力的去清理垃圾来给存活的对象分配空间。

     

    你可能会想,我的应用已经好好的跑了很长时间了,为什么忽然就发生连续的FullGC了?这是个好问题,可能是因为以下原因:

    1.可能是自从上次调优JVM的内存以后,应用的流量忽然变大了!可能是业务量增加了,用户数量变多了。

    2.在业务峰值期间应用创建了比平时更多的对象,可能你并没有对峰值时候的应用内存做调优,或者是说应用峰值时候的流量变大了。

     

    10、如何来解决连续的FullGC?

    1.增加JVM的堆内存

    因为连续的FullGC主要是由于内存不足引起的,增加JVM的堆内存可以解决这个问题。比如之前给应用分配的是2.5G的堆内存,现在增加到3G看能否解决问题,

    通过给JVM传递-Xmx参数可以设置JVM的最大堆内存。-Xmx3G就设置了JVM的最大堆内存是3G。如果还是没解决问题,一点点的继续增加JVM的堆内存。

    不要给JVM分配过多的堆内存,因为这会增加GC的停顿时间。

    2.增加Perm或者Metaspace内存

    如果Perm区或者是Metaspace太小也会导致连续的FullGC,这种情况下就需要增大Perm或者是Metaspace的内存。

    3.增加更多的JVM实例

     

    另一个解决此问题的办法就是增加更多的JVM实例。当有更多的JVM实例以后,应用流量就会分摊到这些实例上,单个JVM承担的流量就降低了,

    那么它上面需要创建的对象随之也变少了,此时可能就不会有连续的FullGC了。

     

    11、JVM内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存。

    思路: 先画出Java内存模型图,结合例子volatile ,说明什么是重排序,内存屏障,最好能给面试官写以下demo说明。

    Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,

    线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,

    线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。

     

    12、java内存模型中堆和栈的区别

    1,管理方式,堆需要GC,栈自动释放

        2.大小不同,堆比栈大

        3.碎片相关:栈产生的碎片远小于堆,因为GC不是实时的

        4.分配方式:栈支持静态分配内存和动态分配,堆只支持动态分配

        5.效率:栈的效率比堆高

     

    13、指令重排

    代码指令可能并不是严格按照代码语句顺序执行的。大多数现代微处理器都会采用将指令乱序执行(out-of-order execution,简称OoOE或OOE)的方法,在条件允许的情况下,

    直接运行当前有能力立即执行的后续指令,避开获取下一条指令所需数据时造成的等待3。通过乱序执行的技术,处理器可以大大提高执行效率。而这就是指令重排。

     

     

    14、内存屏障

    也叫内存栅栏,是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。

     

    LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。

    StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。

    LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

    StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能

     

    展开全文
  • java面试JVM性能优化

    万次阅读 2020-09-27 23:38:28
    文章目录1、Java类加载过程2、java内存分配3、JVM加载Class文件的原理机制?4、GC是什么?为什么要有GC?5、简述Java垃圾回收机制。6、如何判断一个对象是否存活?(或者GC对象的判定方法)7、 垃圾回收的优点和原理。并...

    1、Java类加载过程

    Java类加载需要经历一下7个过程:

    1. 加载

      1. 通过一个类的全限定名获取该类的二进制流。
      2. 将该二进制流中的静态存储结构转化为方法去运行时数据结构。
      3. 在内存中生成该类的Class对象,作为该类的数据访问入口。
    2. 验证

      验证的目的是为了确保Class文件的字节流中的信息不回危害到虚拟机。在该阶段主要完成以下四钟验证:

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

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

    4. 解析

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

    1. 初始化

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

    1. 使用

    2. 卸载

    2、java内存分配
    1. 寄存器:我们无法控制。

    2. 静态域:static定义的静态成员。

    3. 常量池:编译时被确定并保存在.class文件中的(final)常量值和 一些文本修饰的符号引用(类和接口的全限定名,字段的名称和描述符, 方法和名称和描述符)。

    4. 非RAM存储:硬盘等永久存储空间。

    5. 堆内存:new创建的对象和数组,由Java虚拟机自动垃圾回收器管理, 存取速度慢。

    6. 栈内存:基本类型的变量和对象的引用变量(堆内存空间的访问地 址),速度快,可以共享,但是大小与生存期必须确定,缺乏灵活性。

    JVM的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它 在JVM启动的时候被创建。对象所占的堆内存是由自动内存管理系统也就 是垃圾收集器回收。

    堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不 会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收 掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆 内存空间。

    3、JVM加载Class文件的原理机制?

    Java语言是一种具有动态性的解释型语言,类(Class)只有被加载到JVM后才能运行。当运行指定程序时,JVM会将编译生成的.class文件按照需求和一定的规则加载到内存中,并组织成为一个完整的Java应用程序。这个加载过程是由类加载器完成。具体来说,就是由 ClassLoader和它的子类来实现的。类加载器本身也是一个类,其实质是把类文件从硬盘读取到内存中。

    类的加载方式分为隐式加载和显示加载。隐式加载指的是程序在使用new等方式创建对象时,会隐式地调用类的加载器把对应的类加载到JVM中。显示加载指的是通过直接调用class.forName()方法来把所需的类加载 到JVM中。

    任何一个工程项目都是由许多类组成的,当程序启动时,只把需要的类加载到JVM中,其他类只有被使用到的时候才会被加载,采用这种方法一方面可以加快加载速度,另一方面可以节约程序运行时对内存的开销。此 外,在Java语言中,每个类或接口都对应一个.class文件,这些文件可以被看成是一个个可以被动态加载的单元,因此当只有部分类被修改时,只需要重新编译变化的类即可,而不需要重新编译所有文件,因此加 快了编译速度。

    在Java语言中,类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保证程序运行的基础类(例如基类)完全加载到JVM中,至于其他类,则在需要的时候才加载。

    类加载的主要步骤:

    1. 装载。根据查找路径找到相应的class文件,然后导入。
    2. 链接。链接又可分为3个小步:
    3. 检查,检查待加载的c lass文件的正确性。
    4. 准备,给类中的静态变量分配存储空间。
    5. 解析,将符号引用转换为直接引用(这一步可选)
    6. 初始化。对静态变量和静态代码块执行初始化工作。
    4、GC是什么?为什么要有GC?

    GC是垃圾收集的意思(GabageCollection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自 动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方 法。

    5、简述Java垃圾回收机制。

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

    6、如何判断一个对象是否存活?(或者GC对象的判定方法)

    判断一个对象是否存活有两种方法:

    1. 引用计数法

    所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一。当一个对象的引用计数器为零时,说明此对象没有被引用,也就是“死对象”,将会被垃圾回收。

    引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,那么此时A、B对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法。

    1. 可达性算法(引用链法)

    该算法的思想是:从一个被称为GC Roots的对象开始向下搜索,如果一个对象到GCRoots没有任何引用链相连时,则说明此对象不可用。

    在Java中可以作为GC Roots的对象有以下几种:

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

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

    7、 垃圾回收的优点和原理。并考虑2种回收机制。

    Java语言中一个显著的特点就是引入了垃圾回收机制,使C++程序员最 头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候 不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再 有’作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的 防止内存泄露,有效的使用可以使用的内存。

    垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者 长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收 器对某个对象或所有对象进行垃圾回收。

    回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收。

    8、 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

    对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、 大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中 的所有对象。通过这种方式确定哪些对象是”可达的",哪些对象是”不可达 的”。当GC确定一些对象为“不可达”时,GC就有责任回收这些内存空 间。可以。程序员可以手动执行System.gc(),通知GC运行,但是 Java语言规范并不保证GC 一定会执行。

    9、 Java中会存在内存泄漏吗,请简单描述。

    所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存 中。Java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即 对象变成了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉。由于 Java使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题, 例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是 可以回收它们的。

    Java中的内存泄露的情况:

    长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是Java中内存泄露 的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再 使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃 圾回收器回收的,这就是java中可能出现内存泄露的情况。

    例如,缓存系统,我们加载了一个对象放在缓存中(例如放在一个全局map对象中), 然后一直不再使用它,这个对象一直被缓存引用,但却不再被使用。
    检查Java中的内存泄露,一定要让程序将各种分支情况都完整执行到程 序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象 属于内存泄露。
    如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内 部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内 部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会 造成内存泄露。

    10、深拷贝和浅拷贝。

    浅拷贝就是对对象中的数据成员进行简单赋值,如果存在动态成员或者指针就会报错。

    深拷贝就是对对象中存在的动态成员或指针重新开辟内存空间。

    11、System.gc()和 Runtime.gc()会做什么事情?

    这两个方法用来提示JVM要进行垃圾回收。但是,立即开始还是延迟进行垃圾回收是取决于JVM的。

    12、finalize()方法什么时候被调用?析构函数(finalization)的目的是什么?

    垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的 finalize方法,但是在Java中很不幸,如果内存总是充足的,那么垃圾回 收可能永远不会进行,也就是说filalize可能永远不被执行,显然指望它 做收尾工作是靠不住的。

    finalize()最主要的用途是回收特殊渠道申请的内存。Java程序有垃圾回收器,所以一般情况 下内存问题不用程序员操心。但有一种JNI(Java Native Interface)调用non-Java程序(C或C++), finalize()的工作就是回收这部分的内存。

    13、如果对象的引用被置为null,垃圾收集器是否会立即释放对象占用的内存?

    不会,在下一个垃圾回收周期中,这个对象将是可被回收的。

    14、什么是分布式垃圾回收(DGC)?它是如何工作的?

    DGC叫做分布式垃圾回收。RMI使用DGC来做自动垃圾回收。因为RMI 包含了跨虚拟机的远程对象的引用,垃圾回收是很困难的。DGC使用引 用计数算法来给远程对象提供自动内存管理。

    15、串行(serial)收集器和吞吐量(throughput )收集器的区别是什么?

    吞吐量收集器使用并行版本的新生代垃圾收集器,它用于中等规模和大规 模数据的应用程序。而串行收集器对大多数的小应用(在现代处理器上需 要大概100M左右的内存)就足够了。

    16、在Java中,对象什么时候可以被垃圾回收?

    当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。

    17、简述Java内存分配与回收策率以及Minor GC和Major GC。
    1. 对象优先在堆的Eden区分配
    2. 大对象直接进入老年代
    3. 长期存活的对象将直接进入老年代

    当Eden区没有足够的空间进行分配时,虚拟机会执行一次Minor GCO Minor GC通常发生在新生代的Eden区,在这个区的对象生存期短,往 往发生Gc的频率较高,回收速度比较快;

    Full GC/Major GC发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过 配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。

    18、JVM的永久代中会发生垃圾回收么?

    垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。

    注:Java 8中已经移除了永久代,新加了一个叫做元数据区的native内存区。

    19、Java中垃圾收集的方法有哪些?

    标记-清除

    这是垃圾收集算法中最基础的,根据名字就可以知道,它的 思想就是标记哪些要被回收的对象,然后统一回收。这种方法很简单,但是会有两个主要问题:

    1. 效率不高,标记和清除的效率都很低;
    2. 会产生大量不连续的内存碎片,导致以后程序在分配较大的对象时,由于没有充足的连续内存而提前触发一次GC动作。

    复制算法

    为了解决效率问题,复制算法将可用内存按容量划分为相等的两 部分,然后每次只使用其中的一块,当一块内存用完时,就将还存活的对 象复制到第二块内存上,然后一次性清楚完第一块内存,再将第二块上的 对象复制到第一块。但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。

    于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存 划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存 区叫Survior区。每次都会优先使用Eden区,若Eden区满,就将对象 复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多, 以至于Survivor不够时,会将这些对象通过分配担保机制复制到老年代
    中。(java堆又分为新生代和老年代)

    标记-整理

    该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高时,也解决了复制算法的效率问题。它的不同之处 就是在清除对象的时候现将可回收对象移动到一端,然后清除掉端边界以 外的对象,这样就不会产生内存碎片了。

    分代收集

    现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周 期,将堆分为新生代和老年代。在新生代中,由于对象生存期短,每次回 收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活 率较高,没有额外的空间进行分配担保。

    20、什么是类加载器,类加载器有哪些?

    实现通过类的权限定名获取该类的二进制字节流的代码块叫做类加载器。 主要有一下四种类加载器:

    1. 启动类加载器(BootstrapCIassLoader)用来加载Java核心类库,无法被 Java程序直接引用。

    2. 扩展类加载器(extensions class loader):它用来加载Java的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加 载Java类。

    3. 系统类加载器(system class loader):它根据Java应用的类路径 (CLASSPATH)来加载Java类。一般来说,Java应用的类都是由它来完成 加载的。可以通过 ClassLoader.getSystemClassLoader。来获取它。

    4. 用户自定义类加载器,通过继承java.lang.ClassLoader类的方式实现。

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

    展开全文
  • JVM高级内存优化面试

    2017-12-26 15:16:00
    JVM内存分布程序计数器:是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。程序中的分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。由于多线程是通过线程轮流切换...
      1. Sun HotSpot VM,是JDK和Open JDK中自带的虚拟机,也是目前使用范围最广的Java虚拟机。

      2. JVM内存分布

        程序计数器:是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。程序中的分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。由于多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,故该区域为线程私有的内存。
        虚拟机栈:描述的是Java方法执行的内存模型,用于存储局部变量表、操作数栈、动态链接、方法出口等
        堆:是Java虚拟机所管理的内存中最大的一块,Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,存放所实例,也是垃圾收集器管理的主要
        方法区:用于存放已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。HotSVM针对该区域也进行GC,主要是常量回收以及类

      3. JVM内存分配策略
        对象的内存分配,在大方向上,是在Java堆上进行分配。
        大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。
        大多数情况下,大对象直接进入老年代,虚拟机提供了参数来定义大对象的阀值,超过阀值的对象都会直接进入老年代。
        经过多次Minor GC后仍然存活的对象(长期存活的对象),将进入老年代。虚拟机提供了参数,可以设置阀值。

      4. JVM垃圾回收算法
        标记-清除算法:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
        复制算法:将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当一块内存用完了,将还存另外一块上面,然后在把已使用过的内存空间一次清理掉。
        标记-整理算法:标记过程与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所一端移动,然后直接清理掉端边界以外的内存。
        分代收集算法:一般是把Java堆分为新生代和老年代,根据各个年代的特点采用最适当的收集算法。新生代都发现有大批对象死去,选用复制算法。老年代中因为对象存活率高,必须使用“标记-清理”或“标记-整理”算法来进行回收。

      5. 垃圾收集器
        Serial收集器:是一个单线程的收集器,只会使用一个CPU或一条收集线程去完成垃圾收集工作,在进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
        ParNew收集器:是Serial收集器的多线程版本,除了使用多条线程进行垃圾收集之外,其余行为与Serial收集器完全一样。
        CMS收集器:是一种以获取最短回收停顿时间为目标的收集器。过程分为以下四个步骤:
            初始标记
            并发标记
            重新标记
            并发清除

      6. JVM常见启动参数
        -Xms / -Xmx — 堆的初始大小 / 堆的最大大小
        -Xmn — 堆中年轻代的大小
        -XX:-DisableExplicitGC — 让System.gc()不产生任何作用
        -XX:+PrintGCDetails — 打印GC的细节
        -XX:+PrintGCDateStamps — 打印GC操作的时间戳
        -XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小
        -XX:NewRatio — 可以设置老生代和新生代的比例
        -XX:PrintTenuringDistribution — 设置每次新生代GC后输出幸存者乐园中对象年龄的分布
        -XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老年代阀值的初始值和最大值
        -XX:TargetSurvivorRatio:设置幸存区的目标使用率

      7. JAVA类生命周期
        Java类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载七个阶段。

      8. JVM类加载
        启动(Bootstrap)类加载器:是用本地代码实现的类装入器,它负责将 <Java_Runtime_Home>/lib下面的类库加载到内存中(比如rt.jar)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。
        标准扩展(Extension)类加载器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现Java_Runtime_Home >/lib/extjava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
        系统(System)类加载器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。径(CLASSPATH)中指定的类库加载到内存中。开发者可以直接使用系统类加
        双亲委派机制描述 :某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

      9. JVM调优
        查看堆空间大小分配(年轻代、年老代、持久代分配)
        垃圾回收监控(长时间监控回收情况)
        线程信息监控:系统线程数量
        线程状态监控:各个线程都处在什么样的状态下
        线程详细信息:查看线程内部运行情况,死锁检查
        CPU热点:检查系统哪些方法占用了大量CPU时间
        内存热点:检查哪些对象在系统中数量最大

    转载于:https://www.cnblogs.com/zx-bob-123/p/8118116.html

    展开全文
  • 1 jvm优化静态变量的常量池 题目: 写出下面程序的执行结果 public class Demo { final static int num=10; final int ns = 11; static { System.out.println("Demo静态块"); } public Demo() { System.out...

    1 jvm优化静态常量的常量池

    题目: 写出下面程序的执行结果

    public class Demo {
    
        final  static int num=10;
        final int ns = 11;
    
        static {
            System.out.println("Demo静态块");
        }
    
        public Demo() {
            System.out.println("Demo无参构造方法");
        }
    }
    
    class Test {
        public static void main(String[] args) {
            System.out.println(Demo.num);
        }
    }
    

    如果你的答案是:

    Demo静态块
    10
    

    那么恭喜你答错了, 有人会问Demo.num不是加载Demo类了吗? 静态块为什么没执行?

    其实当在类中声明并初始化静态常量时, jvm为了优化静态常量, 会把静态常量放进常量池, 这样当我们用类名调用静态常量时, 其实并没有去加载类, 而是从常量池中取出.

    这种情况只会发生在你只去访问哪个类的静态常量时

    所以正确答案是

    10
    
    展开全文
  • JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的 集合中,进行回收。...
  • jvm常见面试

    千次阅读 2019-04-22 00:34:45
    GC垃圾回收中的垃圾指的是什么?简单的来说是内存中已经不再使用到的空间就是垃圾 如何判断一个对象是否应该回收? 引用计数法 枚举根节点可达性分析(GCRoots) ...你说你做过jvm优化和参数配置,请问如何盘点查...
  • JVM 在对代码执行的优化可分为运行时(runtime)优化和即时编译器(JIT)优化。运行时优化主要是解释执行和动态编译通用的一些机制,比如说锁机制(如偏斜锁)、内存分配机制(如 TLAB)等。除此之外,还有一些专门...
  • 面试官:JVM优化优化了啥?    从JDK1.6开始,JVM对锁进行了各种优化,目的就是为了在线程间更高效的共享数据和解决互斥同步的问题。从锁优化的话题开始,可以引申出很多考点面试题,比如锁优化的技术、各优化...
  • Tomcat JVM 优化

    2018-08-15 17:17:51
    前段时间参加面试面试过程中提到服务器的调优方案,这里总结一下。  首先说一下tomcat的调优方案:  Tomcat本身的优化,Java虚拟机调优,Tomcat 优化分为系统优化,接下来一个个介绍:    一、Tomcat本身...
  • 上文提到了阿里最常用的四种性能优化,本文带大家来了解下jvm性能优化JVM 是小白 Java 程序员成长路上的一道坎,学习JVM之前,只需要知道代码编译成 Class,虚拟机加载 Class 运行就可以了,学习 JVM 之后,可以...
  • 你有遇到过这些问题吗?运行着的线上系统突然卡死,系统无法访问,甚至直接OOM!新项目上线,对各种JVM参数设置一脸茫然,直接默认吧,然后就……想解决线上JVM GC问题,但却无从下手。每...
  • 你有遇到过这些问题吗?运行着的线上系统突然卡死,系统无法访问,甚至直接OOM!新项目上线,对各种JVM参数设置一脸茫然,直接默认吧,然后就……想解决线上JVM GC问题,但却无从下手。每...
  • JVM常见面试

    2018-04-04 17:06:31
    1. 内存模型以及分区,需要详细到每个区...5. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?6. GC收集器有哪些?CMS收集器与G1收集器的特...
  •   JVM面试JVM面试题一、Java类加载过程? 一、Java类加载过程?   Java 类加载需要经历以下7个过程: 1、加载   加载是类加载的第一个过程,在这个阶段,将要完成如下的三件事情: 通过一个类的全限定名...
  • 背景:用来总结java面试过程中与jvm相关的问题。垃圾回收以及优化总结介绍常用的垃圾回收算法,垃圾收集器,垃圾收集器相关的调试参数。调优参数jvm调优三大参数:-Xss规定了每个线程堆栈的大小。一般情况下256K是...
  • 面试题必问的jvm性能优化相关,如何在实际项目中优化jvm,解决项目中性能问题。提升系统的稳定性,以及可维护性。
  • JVM必备面试题(一)

    2020-12-28 20:41:51
    JVM是Java运行基础,面试时一定会遇到JVM的有关问题,内容相对集中,但对只是深度要求较高. 其中内存模型,类加载机制,GC是重点方面.性能调优部分更偏向应用,重点突出实践能力.编译器优化和执行模式部分偏向于理论基础,...
  • 这里简单阐述下我个人对jvm优化的了解,欢迎大家帮忙补充 虽然jvm内存模型分为5块,但是jvm优化主要在堆这里,堆是存放对象的内存空间,优化这个空间其实就是为了防止stop-the-world的发生,也就是full gc 关于...
  • (1)面试必问之jvm与性能优化(1)
  • 我在专栏上一讲介绍了微基准测试和相关的注意事项,其核心就是避免 JVM 运行中对 Java 代码的优化导致失真。所以,系统地理解 Java 代码运行过程,有利于在实践中进行更进一步的调优。 今天我要问你的问题是,JVM ...
  • JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的 集合中,进行回收。...
  • java面试资料 当虚拟机启动时,解释器可以首先发挥作用,而不必等待编译器全部编译完成再执行,这样可以省去许多不必要的编译时间。并且随着程序运行时间的推移,编译器逐渐发挥作用,根据热点探测功能,,将有价值...
  • 本次课程的笔记非常多,而且内容已经整理了好几个小时了,接着下来内容也会更多,也是大型企业JVM性能调优实战的最后一节,希望对你有帮助!04:JVM性能监控与故障处理工具大型企业JVM性能调优实战之总结17:JVM性能...
  • 自己在学习和面试过程中总结的一些常见面试题 , 包含了java内存模型 , java8以后内存变化. 垃圾回收算法, 常见的垃圾回收器 , G1垃圾回收器的优化 堆外内存如何使用等. 希望和大家共同进步 . 祝拿到满意的...
  • JVM基本介绍以及参数优化JVM的基本结构方法区(Method Area)(Non-Heap)堆(Heap)新生代(Young Generation)老年代 (Old Generation)元空间(Meta Space)(永久代)栈(使用命令``javap -v xxx.class > xxx.txt``输出附加...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,568
精华内容 627
关键字:

jvm优化面试