- 双亲委派模型的特点
定义:如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
优势:
避免类的重复加载
防止核心API库被随意篡改。比如,Java中的Object类,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object在各种类加载环境中都是同一个类。如果不采用双亲委派模型,那么由各个类加载器自己取加载的话,那么系统中会存在多种不同的Object类。
破坏:可以继承ClassLoader类,然后重写其中的loadClass方法,其他方式大家可以自己了解拓展一下。
- 2方法区Method Area
方法区在JDK 8中就是Metaspace,在JDK6或7中就是Perm Space
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 3堆(Heap)
Java对象实例以及数组都在堆上分配。
- 4Java Virtual Machine Stacks(虚拟机栈)
虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个Java线程的运行状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,独有的,随着线程的创建而创建。
每一个被线程执行的方法,为该栈中的栈帧,即每个方法对应一个栈帧。
调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出。
- 5程序计数器 The pc Register
占用内存小,jvm多线程是通过线程轮流切换,并分配处理器执行时间的方式来实现的,在任意时刻,一个处理器只会执行一条线程中的指令,因此为了线程切换后能够恢复到正确的执行位置,每条线程需要一个独立的程序计数器(线程私有)。
1.线程执行的是java方法,则记录的是正在执行的虚拟机字节码指令的地址。
2.线程执行的是Native方法,则这个计数器为空。
- 6本地方法栈(Native Method Stacks)
如果当前线程执行的方法是Native类型的,这些方法就会在本地方法栈中执行。
- 7是否需要使用G1收集器?
(1)50%以上的堆被存活对象占用
(2)对象分配和晋升的速度变化非常大
(3)垃圾回收时间比较长
- 8JVM参数可以加上下面两句,这样内存溢出时,会自动dump出该文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof
- 9GC日志分析工具
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps
-Xloggc:gc.log
在线
http://gceasy.io
GCViewer
- 10G1调优
(1)使用G1GC垃圾收集器: -XX:+UseG1GC
(2)调整内存大小再获取gc日志分析
-XX:MetaspaceSize=100M -Xms300M -Xmx300M |
(3)调整最大停顿时间
-XX:MaxGCPauseMillis=20 设置最大GC停顿时间指标 |
(4)启动并发GC时堆内存占用百分比
-XX:InitiatingHeapOccupancyPercent=45 G1用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比例。值为 0 则表示“一直执行GC循环)'. 默认值为 45 (例如, 全部的 45% 或者使用了45%). |
(1)内存泄漏与内存溢出的区别
内存泄漏:对象无法得到及时的回收,持续占用内存空间,从而造成内存空间的浪费。
内存溢出:内存泄漏到一定的程度就会导致内存溢出,但是内存溢出也有可能是大对象导致的。
(2)young gc会有stw吗?
不管什么 GC,都会有 stop-the-world,只是发生时间的长短。
(3)major gc和full gc的区别
major gc指的是老年代的gc,而full gc等于young+old+metaspace的gc。
(4)G1与CMS的区别是什么
CMS 用于老年代的回收,而 G1 用于新生代和老年代的回收。
G1 使用了 Region 方式对堆内存进行了划分,且基于标记整理算法实现,整体减少了垃圾碎片的产生。
(5)什么是直接内存
直接内存是在java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于Java堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存。
(6)不可达的对象一定要被回收吗?
即使在可达性分析法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑阶段”,要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。
被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。
- 11JVM常见参数
- 12JVM的堆
默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小
java堆是所有线程共享的,存放对象实例及数组。
实际上java堆是根据对象存活时间的不同,Java 堆还被分为年轻代、老年代两个区域,年轻代还被进一步划分为 Eden 区、From Survivor 0、To Survivor 1 区。
默认的虚拟机配置比例是Eden:from :to = 8:1:1 。
Java堆 = 老年代 + 新生代
新生代 = Eden + S0 + S1
- 13Jdk1.8 堆栈与之前有什么区别
Jdk1.8之后Metaspace就是方法区。
Jdk1.8移除了永久代PermGen,转变为元空间(Meta space),元空间存放在本地内存中,其最大空间为系统内存空间。通过-XX:MetaspaceSize设置大小,默认为21MB
原因:永久代(PermGen)内存经常溢出
- 14java垃圾收集器
1).Serial 针对新生代,单线程,收集垃圾时,必须stop the world,使用复制算法。
2).ParNew收集器Serial的多线程版本,需要stop the world,复制算法与CMS合作
3).Parallel Scavenge 新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞吐量。如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%
4).Serial old收集器 是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。
5).Parallel old Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法
6).CMS(Current Mark Sweap)是一种以获得最短回收停顿时间为目标的收集器,标记-清除算法
初始标记---并发标记---重新标记---并发清除,收集结束会产生大量空间碎片。
7).G1 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选标记。不会产生空间碎片,可以精确地控制停顿。
- 15G1和CMS的区别
- CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用;
- G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;
- CMS收集器以最小的停顿时间为目标的收集器;
- G1收集器可预测垃圾回收的停顿时间
- CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片
- G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。
- 16Minor GC和Full GC 触发条件
1)young GC:当young gen中的eden区分配满的时候触发。注意young GC中有部分存活对象会晋升到old gen,所以young GC后old gen的占用量通常会有所升高。
2)full GC:当准备要触发一次young GC时,如果发现统计数据说之前young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC(因为HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先触发一次单独的young GC);
或者,如果有perm gen的话,要在perm gen分配空间但已经没有足够空间时,也要触发一次full GC;
或者System.gc()、heap dump带GC,默认也是触发full GC。
17.新生代GC流程
18 GC Root选取:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法
栈的变量等。