java基础

1.String 特性

String的不可变性。
字符串常量池中不会存储相同内容的字符串。
String的String Pool是一个固定大小的HashTable。
使用-XX:StingTableSize=XX 调整HashTable的长度。

2.String内存分配

直接使用双引号(字面量)声明出来的String对象会直接存放在常量池中。
不是通过双引号声明的String对象可以使用intern()方法存放到常量池中。

3.字符串拼接操作

常量与常量的拼接结果在常量池,原理是编译期优化。
常量池中不会存在相同内容的常量。
只要其中有一个是变量(变量非final),结果就在堆中相当与new String(),变量拼接的原理是StringBuilder。
如果拼接的结果调用intern ()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。

4.new String(“ab”)会创建几个对象?

两个。
一个是new 出来的
第二个是 字符串常量中“ab”,看字节码ldc。

5.new String(“a”)+new String(“b”)创建几个对象?

两个。
一个是new 出来的
第二个是 字符串常量中“ab”,看字节码ldc。

6.intern()使用

JDK6中,将字符串对象放入字符串常量池中。
如果池中有,则并不会放入。返回已有字符串常量池中的对象的地址。
如果没有,会把此对象复制一份,放入串池,并返回串池中的对象地址。
JDK7起,将这个字符串对象尝试放入串池。
如果串池中有,则不会放入。返回已有字符串常量池中的对象的地址。
如果没有,则会把对象的引用地址复制一份,放入池中,并返回串池中的引用地址。

7.什么是垃圾。

垃圾是指运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。

8.为什么需要GC

如果不进行垃圾回收,内存迟早都会被消耗完。
JVM整理出内存分配给新对象。
没有GC就不能保证应用程序的正常运行。

9.垃圾回收重点区域

从次数上讲:
频繁收集新生代。
较少收集老年代。
基本不动方法区。

10.垃圾回收过程

垃圾标记阶段:对象存活判断
在执行GC垃圾回收之前,首先需要区分内存中哪些是存活对象,哪些是死亡的对象,被标记已经死亡的对象,GC在执行垃圾回收时释放其所占用的内存空间,这个过程被称为垃圾标记阶段。
对象存活一般有两种方式:引用计数算法和可达性分析算法。
引用计数算法(java不使用):对每个对象保存一个整列的引用计数器属性,用于记录对象被引用的情况。
优点:实现简单,垃圾对象便于识别,判定效率高,回收没有延迟性。
缺点:
他需要单独的字段存储计数器,增加存储空间的开销。
每次复制都需要更新计数器,伴随加法和减法操作,增加时间开销。
引用计数器有一个严重的问题,无法处理循环引用。
可达性分析算法(或根搜索算法、追踪性垃圾收集–java使用的):按照自上至下的方式搜索被根对象集合所连接的目标对象是否可达。
垃圾清理阶段:
成功区分内存存活对象和死亡对象后,GC接下来任务是执行垃圾回收,释放无用对象占用的空间。
目前比较常见的三种垃圾收集算法:
标记-清除算法(mark-sweep):当堆中有效内存空间被耗尽的时候,就会停止整个程序,然后进行两项工作,一是标记,二是清除。
标记:collector从引用根节点开始遍历,标记被引用的对象。一般是在对象的Header中记录为可达对象。
清除:collector对堆内存从头到尾进行线性遍历,如果发现某个对象在Header中没有标记为可达对象,则将其回收。

标记-清除算法缺点:
执行效率不高
进行GC时,需要停止用户程序,体验差。
清除出的空闲内存不连续,会产出内存碎片(导致大对象存储空间不够),需要维护一个空闲列表。
标记-清除算法的清除:这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲地址列表中,下次有新对象需要加载时,判断垃圾的位置空间是都足够,如果够就存放。
复制算法(copying–>新生代垃圾回收使用):将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。

复制算法优点:
没有标记和清除的过程,实现简单,运行高效。
复制过去以后保证空间的连续性,不会出现“碎片为题”。
复制算法缺点:
需要两倍的内存空间。
对于G1这种分拆称为大量region的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,不管是内存占用或者时间开销较多。
复制算法注意:复制算法需要复制存活的对象数量不会太大,如果对象太多,复制算法效果很不理想。
标记-压缩算法(或标记-整理、mark-compact)
执行过程:
第一阶段标记与标记-清除算法一样,从根节点开始标记所有被引用的对象。
第二阶段将所有的存活对象压缩到内存的一端,按顺序排放,之后清理边界外的所有空间。
优点:
消除标记-清除算法中,内存区域分散的缺点。
消除复制算法中内存减半的高额代价。
缺点:
从效率上来说,标记-整理算法要低于复制算法。
移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址。
移动过程中,需要全程停止用户应用程序,即:STW。
小结-三种算法对比

11.分代收集算法

不同生命周期的对象可以采用不同的收集方式,一边提高回收效率。
年轻代:区域相对老年代较小,对象生命周期短、存活率低,回收频繁。这个情况使用复制算法的回收整理。
老年代:区域较大,对象生命周期长、存活率高,回收不及年轻代频繁。一般是由标记-清除或者标记-清除与标记-整理混合实现。
Mark阶段的开销与存活对象的数据成正比。
Sweep阶段的开销与所管理的区域大小成正相关。
Compact阶段的开销与存活对象的数据成正比。
13.增量收集算法
如果一次性将所有的垃圾进行处理,需要造成系统长时间的停顿,那么就可以让垃圾收集线程和应用程序线程交替执行。每次,垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。依次反复,直到垃圾收集完成。
目的:对线程冲突的妥善处理,允许垃圾收集线程以分阶段的方式完成标记、清理或者复制工作。
缺点:线程切换和上下文转换的消耗,会使得垃圾回收的总体成本上升,造成系统吞吐量的下降。

12.分区算法

分区算法将按照对象的生命周期长短分成两个部分,分区算法将整个堆空间划分成连续的不同小区间(region),每一个小区间都独立使用,独立回收。好处是可以一次控制回收多少个小区间。

13.GC Roots包含的元素

虚拟机栈中引用的对象
本地方法栈内JNI引用的对象。
方法区中类静态属性引用的对象。
比如字符串常量池里的引用。
所有被同步锁synchronized持有的对象。
Java虚拟机内部的引用。
基本数据类型对应的Class对象,一些常驻的异常对象,系统类加载器。
反应Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
根据用户所选垃圾收集器以及当前回收的内存区域不同,还可以有其它对象“临时性”的加入,共同构成完整GC Roots集合,比如分代收集和局部回收(Partial GC)。
如果只针对Java堆中某一块区域进行垃圾回收(比如典型只针对新生代),必须要考虑到内存区域是虚拟机自己实现的细节,更不是孤立封闭的,这个区域的对象完全有可能被其他区域的对象所引用,这是就需要一并将关联的区域对象也加入GC Roots集合中考虑。

14.对象finalization机制

java提供了对象终止(finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。
当垃圾回收器发现没有引用指向一个对象,即:回收此对象之前,总会先调用这个对象的finalize()方法。
finalize()方法允许在子类中被重写,用于在对象被回收时进行资源释放。
不要主动调用finalize方法,理由如下:
在finalize()时可能会导致对象复活。
finalize()方法执行时间是没有保障的,由GC线程决定,极端情况下,不发生GC,则不会触发finalize()方法。
一个糟糕的finalize()会严重影响GC性能。
由于finalize()方法的存在,虚拟机中对象一般处于三个可能的状态。
可触及的:从根节点开始,可以到达这个对象。
可复活的:对象的所有引用都被释放,但是对象有可能在finalize()中复活。
不可触及的:对象的finalize()被调用,并且没有复活,那么就会进入不可触及状态,不可触及的对象不可能被复活,因为finalize()只能被调用一次。
回收objA具体流程:
如果对象objA到GC Roots没有引用链,则进行第一次标记。
进行筛选,判断此对象是否有必要执行finalize()方法
如果对象没有重写finalize()方法,后者finalize()方法已经被执行过了,objA被判断不可触及的。
如果对象objA重写了finalize()方法,且还未执行过,那么objA会被插入到F-Queue队列中,由虚拟机自动创建的、低优先级的Finalizer线程触发其finalize()方法。
finalize()方法是对象逃脱死亡的最后机会,如果objA在finalize()方法中与引用链上的任何一个对象建立了联系,在第二次标记时,objA会被移除“即将回收”集合。之后,对象会再次出现没有引用存在的情况,在这个情况下,finalize()方法不会被再次调用,对象会直接变成不可触及状态。也就是说,一个对象的finalize()方法只会被调用执行一次。

15.System.gc()理解

默认通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。
System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用。
调用System.runFinalization(),强制调用失去引用对象的finalize()方法。
不可达对象回收行为
//buff对象没有被回收
private static void localvarGC1(){
{
byte[] buff = new byte[1010241024];
}
System.gc();
}

//buff对象会被回收
/原因:虽然buff出了作用域,在localvarGC1在局部变量表中还有buff槽被占用,
// 而localvarGC2中buff变量槽被value占用,byte数组没有引用指向
/
private static void localvarGC2(){
{
byte[] buff = new byte[1010241024];
}
int value = 2;
System.gc();
}

//原因与localvarGC2类似
private static void localvarGC3(){
localvarGC1();
System.gc();
}

16.Java内存溢出与内存泄漏

内存溢出(OOM):没有空闲内存,并且垃圾收集器也无法提供更多内存。
原因:
Java虚拟机的堆内存设置不够。
代码中创建大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)。
分配超大对象超过堆的最大值,JVM不会执行GC,直接抛出OOM。
内存泄漏:
严格来说,对象不会被程序引用,但是GC不能回收他们的情况,这个情况叫做内存泄漏。
宽泛来说,对象生命周期过长,GC无法回收,会导致OOM,这周叫做宽泛意义的内存泄漏。

举例:
静态集合类
public class MemoryLeak {
static List list = new ArrayList<>();
public void add(){
list.add(new Object());
}
}
单例模式:单列的生命周期和应用程序一样长,如果单例持有外部对象的引用,当这个对象不使用的时候,对象是不能被回收的,会导致内存泄漏的产生。
内部类持有外部类:如果一个外部类的实例对象的方法返回了一个内部类的实例对象。
变量不合理的作用域:一般而言, 一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为nu11,很有可能导致内存泄漏的发生。
HashMap存放,中途修改hash值。
提供close的资源未关闭导致内存泄漏:数据库链接(dataSource.getConnection),网络链接(socket)和io连接必须手动close,否则不能被回收,导致内存溢出。
监听器和回调

17.Stop The World

停顿产生时整个应用程序线程都会停止,没有任何响应,这个停顿称为STW。
可达性分析算法中枚举根节点(GC Root)会导致STW。
分析工作必须在一个能确保一致性的快照中进行
一致性指整个分析期间整个执行系统看起来想被冻结在某个时间点上
如果出现分析过程中对象引用关系还在不断变化,则分析结构的准确性无法保证。
STW事件在所有GC都有发生。
随着垃圾回收器演进,回收效率越来越高,尽可能缩短暂停时间。
STW是在JVM在后台自动发起和自动完成的。
开发中不要使用System.gc(),会导致STW的发生。

18.并行和并发

1)并发(Concurrent):是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一处理器上运行的,并发不是真正意义的“同时执行”,只是CPU把一个时间段划分成几个时间片段,由于CPU切换速度特别快,只要时间处理得到,用户感觉多个应用程序在执行。
2)并行(Parallel):当系统有一个以上的CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,我们称之为并行(Parallel)。
3)二者对比:
并发是指多个事情在同一时间段内同时发生了,多个任务之间相互抢占资源。
并行是指多个事情在同一时间点上同时发生了,多个任务之间不互相抢占资源。
只有在多个CPU或者一个CPU多核的情况下才会发生并行,否则其实都是并发。

19.垃圾回收的并行和并发

并行:多条垃圾收集线程并行工作,用户线程处于等待状态。
如ParNew、Parallel Scavenge、Parallel Old;
串行:相较于并行的概念,单线程执行。

并发(Concurrent):指用户线程与垃圾手机线程同时执行(但一定不是并行的,可能是交替执行),垃圾回收线程在执行时不会停顿用户程序的运行。

20.安全点(SafePoint)

安全点(SafePoint):程序执行时并非所有地方都能停顿下来开始GC,只有特定的位置才能停顿下来开始GC,这些位置被称为“安全点”。
安全点选择很重要,太少导致GC等待时间太长,太多可能导致运行时的性能问题。
安全点选择标准:是否具有让程序长时间执行的特征,如方法调用、循环跳转和异常跳转等。
发生GC时,各个线程如何在安全点停顿下来?
抢先式终端(没有虚拟机在使用):首先终端所有线程,如果还有线程不在安全点,就恢复线程,让线程跑到安全点。
主动式中断:设置一个中断标志,各线程运行到Safe Point的时候主动轮询这个标志,如果中断标记为真,则将自己进行中断挂起。
23.安全区域(Safe Region)
安全区域是指在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的。例如线程处于Sleep状态或者Blocked状态,无法响应JVM的中断请求,这样就需要安全区域。
可以把安全区域看作被扩展的安全点。
实际执行:
当线程运行到Safe Region的代码时,首先标记已经进入Safe Region,如果这段时间发生GC,JVM会忽略标识为Safe Region状态的线程。
当线程即将离开安全区域时,检查JVM是否已经完成GC,如果完成了,则继续运行,否则线程需要等待知道收到可以安全离开Safe Region的信号为止。

21.强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)

前提是引用关系存在
强引用:Object obj = new Object();,无论在任何情况下,只要强引用关系还存在,垃圾收集器就不会回收掉被引用的对象。—OOM也不回收。
软引用:在内存溢出之前,把这些对象列入回收范围之中进行第二次回收。如果这次回收后还没有足够的内存,就会OOM。—内存不够即回收。
弱引用:当垃圾收集器工作时,无论空间是否足够,都会回收弱引用。—发现即回收。
虚引用:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对象的实例。为一个对象设置虚引用关联的唯一目的就是在这个对象被回收时收到系统的一个通知。

22.强引用— OOM也不回收

强引用对象是可触及的,垃圾回收器不会回收强引用对象。
强引用是造成Java内存泄漏的主要原因。
回收条件:指针赋值为null,超过引用作用域。

23.软引用— 内存不足即回收

通常用来实现内存敏感的缓存。
Object obj = new Object()
SoftReference objSoft = new SoftReference(obj)
obj = null;

24.弱引用 — 发现即回收

弱引用关联的对象,只能生存到下一次垃圾收集发生位置
软引用、弱引用非常适合保存那些可有可无的缓存数据。
Object obj = new Object()
WeakReference objSoft = new WeakReference(obj)
obj = null;
WeakHashMap 在内存不足时,k-v会被回收。

25.虚引用 — 对象回收跟踪

所有引用类型中最弱的一个,不能使用get方法获取对象。
虚引用必须和引用队列一起使用。
由于虛引用可以跟踪对象的回收时间,因此,也可以将一些资源释放操作放置在虚引用中执行和记录。

26.垃圾回收器

1)按照线程数区分
串行垃圾回收器
单CPU处理或者较小的应用内存等硬件平台不理想情况下
并行垃圾回收器

2)按工作模式区分
并发式垃圾回收器
独占式垃圾回收器

3)按碎片处理方式区分
压缩式垃圾回收器:再分配对象空间使用—>指针碰撞
非压缩式的垃圾回收器:再分配对象空间使用—>空闲列表
4)按工作的内存区间分
年轻代垃圾回收器
老年代垃圾回收器

27.评估GC的性能指标

吞吐量:运行用户代码时间占总运行时间的比例。
总运行时间 = 程序运行时间 + 内存回收的时间
垃圾收集开销:吞吐量的补数,垃圾收集所用时间与总运行时间的比例。
暂停时间(追求的目标):执行垃圾收集时,程序工作线程被暂停的时间,STW。
收集频率:相对于应用程序的执行,收集操作发生的频率。
内存占用:Java堆区所占的内存大小。
主要抓住两点:吞吐量、暂停时间

1.评估GC的性能指标:吞吐量

吞吐量 = 运行用户代码时间 / (程序运行时间 + 内存回收的时间)。
吞吐量优先意味这单位时间内,STW时间最短。

2.评估GC的性能指标:暂停时间

是指一个时间段内应用程序线程暂停,GC线程执行的时间。
暂停时间优先意味着尽可能让单次STW的时间最短

3.评估GC的性能指标:吞吐量 vs 暂停时间

目前标准:在最大吞吐量优先的情况下,降低停顿时间。

28 款经典垃圾回收器

串行回收器:Serial 、Serial Old
并行回收器:ParNew、Parallel Scavenge、Parallel Old
并发回收器:CMS、G1

29 款垃圾回收器与垃圾分带之间的关系

新生代收集器:Serial、ParNew、Parallel Scavenge;
老年代收集器:Serial Old、Parallel Old、CMS
整堆收集器:G1

30.垃圾收集器组合

1)两个收集器间有连线,表明它们可以搭配使用:
Serial/Serial old、Serial/CMS、ParNew/Serial old、ParNew/CMS、Parallel Scavenge/Serial old、 Parallel Scavenge/Parallel old(JDK8中默认垃圾回收器)、G1(JDK9默认垃圾回收器);
2)其中Serial Old作为CMS出现Concurrent Mode Failure 失败的后备方案。
3)(红色虚线)由于维护和兼容性测试的成本,在JDK 8时将Serial+CMS、ParNew+ Serial Old这个两个组合声明为废弃,在JDK9时完全移除。
4)(绿色虚线)JDK14中:弃用Parallel Scavenge和 Serial Old组合。
5)(蓝色虚线)JDK14中删除CMS垃圾回收器。
6)不可兼容使用的原因是因为Parallel收集器与G1与其他垃圾收集器顶层框架不一致。

31.查看默认垃圾回收器

-XX:+PrintCommandLineFlags:查看命令行相关参数
jinfo -flag 相关垃圾回收器参数 进程id
38.Serial收集器:串行回收
Serial收集器作为HotSpot中Client模式下的默认新生代垃圾收集器。
Serial收集器使用复制算法,串行回收,有STW机制执行内存回收。
Serial收集器还提供用于执行老年代垃圾收集的Serial Old收集器。
Serial Old是运行在Client模式下的老年代垃圾回收器。
Serial Old在Server模式下主要有两个用途:(1)与新生代的Parallel Scavenge配合使用。(2)作为老年代CMS收集器的后备垃圾收集方案。
优势:简单而高效。
在HotSpot虚拟机中,使用-XX:+UseSerialGC参数指定年轻代和老年代都是用串行收集器。

32.ParNew收集器:并行回收

Serial GC是年轻代中单线程垃圾收集器,ParNew是Serial多线程版本。
Par是Parallel的缩写,New:只能处理新生代。
ParNew收集器采用并行回收方式、复制算法、STW机制。
对于新生代,回收次数频繁,使用并行方式高效。
对于老年代,回收次数少,使用串行方式节省资源。
通过-XX:UseParNewGC 手动使用ParNew收集器执行内存回收任务。
-XX:ParallelGCThread=size 限制线程数量,默认开启和CPU数据相同的线程数。

33.ParNew与Serial不同场景性能比较。

多CPU环境下,ParNew效率高,可以并行处理。
单CPU环境下,Serial效率高。
41.Parallel Scavenge回收器:吞吐量优先--------JDK8中默认的垃圾收集器
1)并行回收、复制算法、STW机制。
2)与ParNew收集器不同,Parallel Scavenge收集器目标是达到一个可控制的吞吐量,也被成为吞吐量优先的垃圾收集器。
3)自适应调节策略是parallel Scavenge与ParNew的一个重要区别。
4)高吞吐量则可以高效率地利用CPU时间,适合后台运算不需要太多交互任务,例如批量处理、订单处理、工资支付、科学计算。
5)Parallel 在JDK1.6提供Parallel Old 替代 Serial Old收集器
6)Parallel Old收集器采用标记-压缩算法,同样也是基于并行回收、STW机制。
7)参数设置:
-XX:+UseParallelGC 手动指定新生代垃圾收集器。
-XX:+UseParallelOldGC 手动指定老年代垃圾收集器。
UseParallelGC 与UseParallelOldGC互相激活。
-XX:ParallelGCThreads 设置年轻代并行收集器线程数,一般与CPU数量相等。
当CPU个数小于等于8个,ParallelGCThreads的值等于CPU数量
当CPU数量大于8个,ParallelGCThreads的值等于3+[5*CPU_Count]/8。
-XX:MaxGCPauseMillis 设置垃圾回收最大停顿时间(即STW时间),单位是毫秒。该参数工作时会调整Java堆大小或者一些其他参数,慎用。
-XX:GCTimeRatio 设置垃圾收集时间占总时间的比例(=1/(N+1)),用于衡量吞吐量大小。
取值范围(0,100),默认是99,也就是垃圾回收时间不超过1%。
与XX:MaxGCPauseMillis 参数有一定的矛盾性,暂停时间越长,Radio参数就容易超过设定的比例。
-XX:+UseAdaptiveSizePolicy 设置Parallel Scavenge收集器具有的自适应调节策略。
在该模式下,年轻代的大小、Eden和Survivor的比例、晋升老年代的对象参数会被自动调整,已到达在堆大小、吞吐量和停顿时间之间的平衡点。
在手动调优比较困难的场合,可以直接使用这种自适应的方式,仅指定虚拟机的最大堆,目标的吞吐量(GCTimeRadio)和停顿时间(MaxGCPauseMillis),让虚拟机自己完成调优工作。

34.CMS回收器(Concurrent Mark Sweep,JDK14已经移除):低延迟

并发的垃圾回收器,让垃圾收集线程与用户线程同时工作。
关注点:尽可能缩短垃圾收集时用户线程停顿时间
CMS垃圾收集采用标记-清除算法。
CMS工作原理
初始标记(STW):程序中所有线程都会STW出现暂停,任务是仅仅标记出GC Roots能直接关联到的对象。
并发标记(非STW):从GC Roots直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。
重新标记(STW):用于修正并发标记期间,因用户程序继续运到导致标记产生变动的那一部分记录。
并发清除:清理删除掉标记阶段判断的已经死亡的对象,释放内存空间。
标记-清除算法不会影响正在运行的用户线程的引用地址。

触发时机:当堆内存使用率到达某一阈值时,便开始进行回收,以确保应用程序在CMS工作过程中依然有足够的空间支持应用程序运行,若预留内存不足时,则启用Serial Old收集器重新对老年代进行垃圾收集,这样停顿时间就很长了。
优点:并发收集、低延迟。
弊端:
会产生内存碎片,无法存储大对象,不得不提前触发full gc。
CMS收集器对CPU资源非常敏感,在并发阶段会占用一部分线程,总吞吐量降低。
CMS收集器无法处理浮动垃圾,在并发标记阶段,如果用户线程产生新的对象垃圾,CMS将无法对这些对象垃圾进行标记,导致新产生的垃圾对象没有被及时回收。
参数设置
-XX:+UseConcMarkSweepGC:手动指定CMS启用
新生代自动启动-XX:+UseParNewGC
-XX:CMSlnitiatingOccupanyFraction 设置堆内存使用率的阈值。
JDK5以前默认值为68%,JDK6以后默认值为92%
-XX:+UseCMSCompactAtFullCollection:用于指定执行完full gc后对内存空间进行压缩整理。
-XX:CMSFullGCsBeforeCompaction:设置在执行多少次Full GC之后对内存空间进行整理。
-XX:ParallelCMSThreads 设置CMS线程数量
默认启动线程数是(ParallelGCThreads+3 )/4

35.G1(Garbage First)垃圾回收器:区域化分代式 -------JDK9以后默认垃圾处理器

目标:在延迟可控的情况下,尽可能提高吞吐量。
G1是一个并行回收器,把堆内存分割成很多不相关的区域(region)(物理上不连续 )。使用不同的Region来表示Eden、幸存者0区,幸存者1区,老年代等。
G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需的时间的经验值),在后台维护一个优先列表,优先回收价值最大的Region。
G1侧重点在于回收垃圾最大量的区间。
复制算法、标记-压缩算法。

36.G1 GC的垃圾回收过程主要环节:

年轻代GC(yong GC):年轻代垃圾收集器是一个并行的独占式(STW)。
第一阶段,扫描根-----寻找GC Roots
第二阶段,更新RSet:RSet可以准确的反应老年代对所在内存分段中对象的引用。
第三阶段,处理RSet:识别被老年代指向的Eden中的对象,这些被指向的Eden中的对象被认为是存活的对象。
第四阶段,复制对象。
第五阶段,处理引用:处理强弱虚等引用,最终将Eden空间的数据为空,GC停止工作。
老年代并发标记过程(Concurrent Marking):当堆内存使用达到一定值(默认45%),开始老年代的并发标记过程。
第一步,初始标记阶段:标记从根节点直接可达的对象,STW,并且触发一次新生代GC。
第二步,根区域扫描:G1 GC扫描Survivor区直接可达的老年代区域对象,并标记引用的对象,这一过程必须在Young GC之前完成。
第三步,并发标记:若发现区域对象中所有对象都是垃圾,这个区域会立刻被回收。在并发标记中,会计算每个区域对象活性(区域中存活对象的比例)。
第四步,再次标记:由于应用程序持续进行,需要修正上一次的标记结果。G1中采用比CMS更快的初始快照算法:snapshot-at-the-beginning(SATB)。
第五步,独占清理(STW):计算各区域的存活对象和GC回收比例,并进行排序,识别可以混合回收的区域。
第六步,并发清理阶段:识别并清理完全空闲的区域。
混合回收(Mixed GC):标记完成后开始混合回收,G1的老年代回收器不需要整个老年代被回收,只是回收符合时间内价值高的老年代Region,同时老年代Region和年轻代是一起被回收的。
老年代并发标记结束以后,老年代中百分百为垃圾的内存分段被回收了,部分为垃圾的内存分段被计算出来了。默认情况下,这些老年代内存分段会分8次(可以通过-XX:G1MixedGCCountTarget设置)被回收。
混合回收的回收集包括八分之一的老年的内存分段,Eden区内存分段,Survivor区内存分段,回收算法为复制算法,与之前的算法完全一致。
由于老年代中的内存分段默认分8次回收,G1会优先回收垃圾多的内存分段,垃圾占内存分段比例越高,越先被回收。-XX:G1MixedGCLiveThresholdPercent,默认为65%,垃圾占内存分段比例达到65%才会被回收。
混合回收不一定要8次,有一个阈值:-XX:G1HeapWastePercent,默认值为10%,允许整个堆内存中有10%的空间被浪费,如果发现回收的垃圾占堆内存比例小于10%,则不进行混合回收。
(如果需要,单线程、独占式、高强度的Full GC还是继续存在的。他针对GC的评估失败提供了一种失败保护机制,即强力回收)。

37.G1垃圾回收器:Remembered Set

无论是G1还是其他分代收集器,JVM都是使用Remembered Set来避免全局扫描,提高Minor GC效率。
每个Region都有一个对应的Remembered Set。
每次Reference类型数据写操作时,都会产生一个Write Barrier(写屏障)暂时中断操作。
检查将要写入的引用指向的对象是否和该Reference类型在不同Region。
如果不同,通过CardTable把相关引用信息记录到引用指向对象所在Region对应的Remembered Set中。
垃圾收集时,在GC根节点的枚举范围加入Remembered Set,可以保证不进行全局扫描,也不会有遗漏。

38.G1(Garbage First)垃圾回收器特点

并行与并发
并行性:G1在回收期间,可以有多个GC线程同时工作。
并发性:G1拥有与程序交替执行的能力,部分工作可以和应用程序同时执行。
分代收集
将堆空间分为若干区域(Region),这些区域包含了逻辑上的年轻代、老年代。
同时兼顾年轻代、老年代垃圾回收。
空间整合
G1将内存划为不同的Region采用复制算法,整体上可看作标记-压缩算法,避免内存碎片。
可预测的停顿时间模型
分区的原因,G1可以只选取部分区域进行内存回收。
G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需的时间的经验值),在后台维护一个优先列表,优先回收价值最大的Region,保证G1收集器在有限时间内可以获取尽可能高的收集效率。

G1(Garbage First)垃圾回收器缺点

小内存应用CMS表现大概率优于G1,平衡点在6-8G。
需要为每个Region分配Remembered Set,占用内存空间(10%-20%)。

G1(Garbage First)垃圾回收器参数

-XX:+UseG1GC 手动指定使用G1收集器
-XX:G1HeapRegionSize 设置每个Region大小,值为2的幂,范围是1MB到32MB之间。
-XX:MaxGCPauseMillis 设置最大GC停顿时间,默认200ms。
-XX:ParallelGCThread 设置并行GC线程数,最大值为8。
-XX:ConGCThreads 设置并发GC线程数,ParallelGCThreads的1/4左右。
-XX:InitiatingHeapOccupancyPercent 设置并发GC周期的Java堆占用率阀值,超过该值就触发GC,默认值为45。

39.分区Region:化整为零

一个Region只能属于一个角色,角色之间可以转化。
设置H的原因:对于堆中的大对象,默认直接会分配到老年代,但是如果是一个短期的对象,就是对垃圾收集造成负面影响,未解决这个问题,G1划分了一个Humongous区,专门用来存放大对象,如果一个H区装不下,那么G1会寻找连续的H区来存储,为了寻找连续的H区,有时候不得不启用Full GC。
Region区域使用

40.垃圾回收参数

-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出gc详细日志
-XX:PrintGCTimeStamps 输出GC的时间戳(以基准时间)
-XX:PrintGCDateStamps 输出GC的时间戳(以日期的形式)
-XX:PrintHeapAtGC 在进行GC的前后打印出堆的信息。
-Xloggc:…/log/gc.log 日志文件输出路径

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值