Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。
给你学习路线:html-css-js-jq-javase-数据库-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
前言
Java虚拟机的垃圾收集器是虚拟机内存的清道夫,它的存在让Java开发人员能将更多精力投入到业务研发上。了解垃圾收集器,并利用好这个工具,能更好的保障服务稳定性。这篇文章通过分析Java虚拟机内存模型,介绍垃圾收集器常用算法和收集器类别,使得垃圾收集器的配置和使用变得不再遥不可及。
Java虚拟机内存模型
Java虚拟机内存可以划分为:虚拟机栈、本地方法栈、JAVA堆内存、方法区(包含运行时常量池)、程序计数器、直接内存。
虚拟机栈
虚拟机栈是线程私有的,生命周期跟线程相同。也就是说一个线程被创建后,虚拟机为其分配了一个独立的栈帧来存储线程的局部变量、操作数、动态链接、方法出口等信息,当线程结束后,该栈帧也会被回收清理。
小编推荐一个学Java的学习裙【 七六零,二五零,五四一 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!
本地方法栈
本地方法栈是虚拟机的native方法执行期间使用的一个栈帧。
Java堆内存
堆内存是被所有线程共享的一块区域,用来存放对象实例和数组,属于内存中最大的一块区域,也是垃圾收集的主要区域。从垃圾收集的角度看,堆内存经常分为新生代和老年代。
方法区
方法区也是被所有线程共享的一块区域,用来存储被虚拟机加载的类信息、常量、静态变量、JIT编译后代码等数据。也可以成为永久代。
程序计数器
程序计数器是线程私有的,作为当前线程所执行的字节码的行号指示器,每个线程有一个程序计数器,用于记录CPU切换线程时记录当前线程的执行位置,以便下次继续从当前位置往下执行。
直接内存
这块不属于JAVA虚拟机内存,但使用频繁,也可称之为“堆外内存”
Java虚拟机垃圾收集器
根据上述对JAVA虚拟机内存区域模型的介绍,我们知道JAVA程序中的对象实例都存储在JAVA堆内存中,因此垃圾收集主要也是针对堆内存进行。为了更好的管理JAVA对象实例,并结合对象实例的生存时间长短,JAVA虚拟机将堆内存分为新生代和老年代,分别存储刚创建不久的对象和存活较长时间的对象实例,并采用分代收集的策略分别回收新生代和老年代的内存。
内存分配与回收策略
1、 分代收集思路。根据JAVA对象的生存周期特点,虚拟机将堆内存分为新生代和老年代,并分别采用新生代和老年代的垃圾回收策略。
2、 新生代细分为Eden区和两个Survivor区(即From区和To区)。大多数新生对象创建频繁,且存活时间短,为了提高新生代区域垃圾收集效率,新创建的对象存放在Eden区,当Eden区快满的时候,虚拟机对其触发一次Minor GC,将新生代存活对象移动到From区,原来From区的对象根据存活年龄决定放到To区还是老年代,然后清空Eden区和From区,接着将To区对象全部移到From区。
3、 大对象直接进入老年代,可以配置新生代对象的最大值,对象超过这个值就直接进入老年代。
4、 发起Minor GC前,会先判断老年代最大可用连续空间是否大于新生代对象占用的空间,如果小于或不允许冒险,则触发一次Full GC。
垃圾收集算法(3种基本算法)
1、 复制算法。针对于新生代的垃圾收集算法。当新生代Eden区快满的时候,将Eden区对象复制到From区,将From区对象根据存活年龄决定复制到To区还是到老年代,然后清除Eden区和From区,接着将To区对象复制到From区。
2、 标记-清除算法。垃圾收集算法标记出需要回收的对象,标记完成后直接统一回收。垃圾收集器使用可达性分析来判断哪些对象是否存活,通过设置一系列GC Roots节点(包括栈、方法区中的静态属性和常量所引用的对象,以及本地方法栈中引用的对象),从这类节点往下搜索,当对象不在GC Root节点的引用链上时,说明对象不可达,可以被回收。
3、 标记-整理算法。垃圾收集算法标记出需要回收的对象,标记完成后将存活对象往内存的一端移动,然后直接清理掉端边界以外的内存。
小编推荐一个学Java的学习裙【 七六零,二五零,五四一 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!
常用垃圾收集器
由于虚拟机中的垃圾收集是分代收集的,新生代和老年代的垃圾收集策略不太一样,所以一般是使用针对新生代和老年代的垃圾收集器组合。
1、 Serial GC。新生代收集器,采用复制算法,用于Client客户端新生代垃圾收集,针对内存占用较少的应用进行垃圾收集。
2、 Serial Old GC。老年代收集器,采用标记-整理算法,用于Client客户端老年代垃圾收集,针对内存占用较少的应用进行垃圾收集。
3、 Parallel Scavenge GC。新生代收集器,采用复制算法,并行收集新生代内存垃圾,可以设置垃圾收集器的吞吐量,还可以设置自动适配调节吞吐量。
4、 Parallel New GC。新生代收集器,采用复制算法,并行收集新生代内存垃圾。
5、 Parallel Old GC。老年代收集器,采用标记-整理算法,并行收集老年代内存垃圾。
6、 CMS GC。老年代收集器,采用标记-清除算法,并行收集老年代内存垃圾,不整理内存。由于在执行垃圾收集期间不中断业务线程,所以容易产出“浮动垃圾”,导致Full GC。可以通过设置参数来触发内存整理任务。
7、 G1 GC。不再将堆内存区分新生代和老年代,而是将堆内存看作若干个均分小区域,并对最空闲的内存区域进行标记和回收。适用于大内存的应用。
配置垃圾收集机器参数
1、UseSerialGC:虚拟机允许在Client模式下的默认值,打开此配置后,虚拟机使用Serial GC + Serial Old GC 的收集器组合进行内存回收。
2、UseParNewGc:使用ParNew + Serial Old 的收集器组合进行内存回收。
3、UseConcMarkSweepGC:使用ParNew + CMS + Serial Old GC的收集器组合进行内存回收。
4、UseParallelGC:虚拟机允许在Server模式下的默认值,使用Parallel Scavenge + Serial Old 的收集器组合进行内存回收。
5、UseParallelOldGC: 使用Parallel Scavenge + Parallel Old GC的收集器组合进行内存回收。
6、SuriviorRatio:新生代中Eden区域与Surivior区域的容量比值,默认是8:1。
7、PretenureSizeThreshold:设置这个值后,大于这个值的对象直接进入老年代。
8、MaxtenuringThreshold:对象年龄超过这个值时进入老年代。
9、ParallelGCThreads:设置并行GC时进行内存回收的线程数。
10、UseAdaptiveSizePolicy:动态调整堆内存中各个区域的大小和进入老年代的对象年龄。
11、HandlerPromotionFailure:是否允许分配担保失败。
12、GCTimeRatio:仅在Parallel ScaVenge收集器时生效,设置GC时间占总运行时间的比率,默认为1%。
13、MaxGCPauseMills:仅在Parallel ScaVenge收集器时生效,设置GC的最大停顿时间。
小编推荐一个学Java的学习裙【 七六零,二五零,五四一 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!
14、CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发垃圾收集,默认68%,在设置CMS收集器时生效。
15、UseCMSCompactAtFullCollection:在设置CMS收集器时生效,设置CMS收集器在完成垃圾收集后是否进行一次碎片整理。
16、CMSFullGCsBeforeCompaction:仅在使用CMS时生效,设置CMS收集器在进行若干次收集后再启动一次内存碎片整理。