8.垃圾收集有哪些算法,各自的特点?
标记清除
直接将要回收的对象标记,发送gc的时候直接回收:特点回收特别快,但是回收以后会造成
很多不连续的内存空间,因此适合在老年代进行回收,CMS(current mark-sweep),就是采
用这种方法来回收老年代的。
标记整理
就是将要回收的对象移动到一端,然后再进行回收,特点:回收以后的空间连续,
缺点:整理要花一定的时间,适合老年代进行会后,parallel Old(针对parallel
scanvange gc的) gc和Serial old就是采用该算法进行回收的。
复制算法
将内存划分成原始的是相等的两部分,每次只使用一部分,这部分用完了,就将还存活
的对象复制到另一块内存,将要回收的内存全部清除。这样只要进行少量的赋值就能够
完成收集。比较适合很多对象的回收,同时还有老年代对其进行担保。
分代收集
对新生代的对象的收集称为minor GC;
对旧生代的对象的收集称为Full GC;
程序中主动调用System.gc()的GC为Full GC。
9.HotSpot为什么要分为新生代和老年代?
因为有的对象寿命长,有的对象寿命短。应该将寿命长的对象放在一个区,寿命短的对象
放在一个区。不同的区采用不同的垃圾收集算法。寿命短的区清理频次高一点,寿命长的
区清理频次低一点。提高效率。
10.常见的垃圾回收器有那些?
JVM中的垃圾回收器,主要包括串行回收器、并行回收器以及CMS回收器、G1回收器。他们各自都有优缺点,通常来说你需要根据你的业务,进行基于垃圾回收器的性能测试,然后再做选择。下面给出配置回收器时,经常使用的参数:
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:+UseG1GC:启用G1垃圾回收器
现在常见的垃圾收集器有如下几种:
新生代收集器:
Serial
ParNew
Parallel Scavenge
老年代收集器:
Serial Old
CMS
Parallel Old
堆内存垃圾收集器:G1
每种垃圾收集器之间有连线,表示他们可以搭配使用。
或者也可以分为串行的/并行的/G1收集器
串行的:也就是采用单线程(比较老了),分类:serial new(收集年轻代,复制算法)和serial old(收集老年代,标记整理),缺点:单线程,进行垃圾回收时暂时所有的用户线程。优点:实现简单
并行的:采用多线程,对于年轻代有两个: parallel new(简称ParNew)和parallel scavenge;parallel scavenge是一个针对年轻代的垃圾回收器,采用复制算法,主要的优点是进行垃圾回收时不会停止用户线程(不会发生stop all world)
老年代回收器也有两种:Parallel old和CMS。Parallel old是parallel scavenge为老年代设计的。CMS(并发标记清除),他采用标记清除算法,采用这种的优点就是快咯,因此会尽快的进行回收,减少停顿时间。
G1收集器,年轻代和老年代通吃,最新一代的技术。面向服务器端的垃圾收集器(并行+并发的垃圾收集器)整体上标记-整理 局部上 复制
11.介绍一下CMS,G1收集器。
区别一:使用的范围不一样
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用。
G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用。
区别二:使用的算法不一样
CMS收集器是使用“标记-清除”算法进行的垃圾回收。
G1收集器使用的是“标记-整理”算法进行的垃圾回收。
区别三:CMS收集器和G1收集器的优劣性
CMS收集器以最小的停顿时间为目标的收集器,容易产生内存碎片。
G1收集器不会产生内存碎片。
区别四:垃圾回收的过程不一样
CMS收集器:初始标记→并发标记→重新标记→标记清楚
G1收集器:初始标记→并发标记→最终标记→筛选回收
12.Minor Gc和Full GC 有什么不同呢?
区别:
Minor GC又称为新生代GC :指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特 性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
Full GC 又称为 老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了Major GC,经常会伴随 至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。 Major GC的速度一般会比Minor GC慢10倍以上。老年代:标记-整理算法(清理的时候做内存移动)
拓展问题:
1.String类和常量池:
在java的内存分配中,经常听到很多关于常量池的描述,
String 对象的两种创建方式:
String str1 = "abcd"; // 先检查字符串常量池中有没有"abcd"。如果没有,则创建一个,然后 str1 指向字符串常量池中的对象;如果有,则直接将 str1 指向"abcd"
String str2 = new String("abcd"); // 堆中创建一个新的对象
String str3 = new String("abcd"); // 堆中创建一个新的对象
System.out.println(str1==str2); // false
System.out.println(str2==str3); // false
第一种方式,是在常量池中拿对象(str1)
第二种方式,是直接在堆内存空间创建一个新的对象(str2和str3)
只要是使用 new 的方法,便需要创建新的对象
全局字符串池里的内容是在类加载完成,经过验证,准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中(记住:string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的。)。 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个哈希表,里面存的是驻留字符串(也就是我们常说的用双引号括起来的)的引用(而不是驻留字符串实例本身),也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了”驻留字符串”的身份。这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。
class文件常量池(class constant pool) :
我们都知道,class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。 字面量就是我们所说的常量概念,如文本字符串、被声明为final的常量值等。 符号引用是一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可(它与直接引用区分一下,直接引用一般是指向方法区的本地指针,相对偏移量或是一个能间接定位到目标的句柄)。一般包括下面三类常量:
类和接口的全限定名字段的名称和描述符方法的名称和描述符
常量池的每一项常量都是一个表,一共有如下表所示的11种各不相同的表结构数据,这每个表开始的第一位都是一个字节的标志位(取值1-12),代表当前这个常量属于哪种常量类型。 每种不同类型的常量类型具有不同的结构,具体的结构本文就先不叙述了,本文着重区分这三个常量池的概念(读者若想深入了解每种常量类型的数据结构可以查看《深入理解java虚拟机》第六章的内容)。
2.8种基本类型的包装类和常量池
Java 基本类型的包装类的大部分都实现了常量池技术,即 Byte,Short,Integer,Long,Character,Boolean;这 6 种包装类默认创建了数值[-128,127] 的相应类型的缓存数据,而超出此范围的仍然会去创建新的对象
两种浮点数类型的包装类 Float,Double 并没有实现常量池技术