标签:min 结果 交换 内存区域 时间片 虚拟 cms 类对象 用户线程
内存溢出:通俗的说就是系统内存不够,导致程序崩溃,一般内存泄漏很严重会导致内存溢出。
@Test
Public void contextLoads(){
Object obj1 = new Object();
Object obj2 = obj1;
Object obj3 = obj1;
Obj1 = null;
System.out.println(obj2);
System.out.println(obj3);
Obj2 = null;
Obj3 = null;
System.out.println(obj2);
System.out.println(obj3);
}
输出结果:
java.lang.Object@18948cd
java.lang.Object@18948cd
null
null
//相互引用的问题
Object obj1 = new Object();
Object obj2 = new Object();
obj1.object = obj2;
obj2.object = obj1;
obj1 = null;
obj2 = null;
从GC root开始可达的为存活对象,不可达的为待gc对象。
GC Roots的条件:
+ 虚拟机栈的栈桢的局部变量表所引用的对象
+ 本地方法栈的JNI所引用的对象
+ 方法区的静态变量和常量所引用的对象
如下图所示:
从GCRoot开始,如果是可达对象标记为存活对象,然后对不可达对象进行清楚。
简单,需要停止程序,而且Gc后的内存区域零散。
将内存区分为两部分:空闲区域和活动区域。现把可达对象复制到空闲区域,然后把空闲区间变为活动区间,同时把之前的活动区间Gc掉,变为空闲区间。
不需要停止程序,速度快,但是耗费空间
标记可达对象,清除不可达对象,整理内存空间。
其实就是根据不同的内存区域使用不同的垃圾回收算法。
年轻代一般用户存放一些新创建的,生命周期比较短的对象,一定对象失去引用可以立刻被回收的对象。
在年轻代会不定时发生Minor GC。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的。,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。
当survivor1已经无法存放edan和survivor0所有存活的对象时,会把survivor1里面的存活对象,复制到老年代。如果老年代也满了,会触发一次Full GC。即新生代和老年代同时垃圾回收。
老年代大概和新生代的比例是 2:1
一般用于保存多次GC依然存活的生命周期比较长的对象。如果老年代也满了的话,会触发一次FullGC。
一般用于存放静态文件,例如类的信息,方法的信息。
+ 新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge
+ 老年代收集器使用的收集器:Serial Old、Parallel Old、CMS
我们一般关注的是运行时数据区。
堆分为新生代和老年代。
新生代分为Edan,from survival(survival0),to survival(survival1),比例大概是8:1:1
老年代主要用于保存一些在新生代里面多次gc依然存活的对象,一般是15次gc。一般是一些大的对象。老年代和新生代的内存大小比例一般是 2:1。
还有一个持久代(永久代 perm)的区域,一般指的是方法区。表示此空间很少被回收,但是不表示不会被回收。
满足下面条件依然会被垃圾回收:
1.常量池中的常量,常量如果没有被引用则可以被回收
2.无用的类信息(同时满足以下条件):
2.1. 类的所有实例都已经被回收了
2.2. 加载类的ClassLoader已经被回收
2.3. 类对象的class对象没有被引用(即没有通过反射引用该类的地方)
方法区包含
+ ClassLoader引用
+ 字段数据
+ 常量池
+ 方法数据
+ 方法代码
一个java类被类加载器加载后,类的相关的信息会保存到方法区,包括:即加载类时需要加载的信息,包括版本、域、方法、接口等信息,也包括静态变量。
每个jvm实例只有一个方法区,这里会被jvm下的线程共享,so方法区是线程不安全的。
4.2.2.2 本地方法栈(native method stack,有的虚拟机会把本地方法栈和虚拟机栈放到同一个位置。)
4.2.2.3程序计数器(pc寄存器)
从寄存器的概念上我们就可以了解到空间很小但是很重要。主要用于记录代码执行到哪一行的信息。可以理解为当前线程的行号指示器(字节码)字节码解释器在工作时,会通过改变这个计数器的值来取下一条指令。
内存一部分被jvm管理,一部分没有被jvm管理,没有的那部分就是直接内存。
-XmsxxM : -Xms64M 设置最小堆内存为64MB
-Xmxxxm : -XMx128M 设置最大堆内存128MB
-XX:NewSize :设置年轻代的大小
-XX:NewRatio : 设置年轻代和老年代的比值,如:3 表示年轻代与老年代的比值为1:3
-XX:SurvivorRatio :年轻代中eden区与两个survivor区的比值
-XX:MaxPermSize : 设置持久代的大小
没有最好的收集器也没有万能的收集器,只有最合适的收集器。收集器是jvm对于不同算法具体实现,Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、版本的虚拟机所提供的垃圾收集器都可能会有很大差别。
?????? 指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态;
?????? 如ParNew、Parallel Scavenge、Parallel Old;
?????? 指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行);
??????用户程序在继续运行,而垃圾收集程序线程运行于另一个CPU上;????
?????? 如CMS、G1(也有并行);
(A)、Minor GC
?????? 又称新生代GC,指发生在新生代的垃圾收集动作;
?????? 因为Java对象大多是朝生夕灭,所以Minor GC非常频繁,一般回收速度也比较快;
(B)、Full GC
?????? 又称Major GC或老年代GC,指发生在老年代的GC;
?????? 出现Full GC经常会伴随至少一次的Minor GC(不是绝对,Parallel Sacvenge收集器就可以选择设置Major GC策略);
??????Major GC速度一般比Minor GC慢10倍以上;
收集器之间有连线表示可以配合使用。
新生代收集器:Serial、ParNew、Parallel Scavenge;
老年代收集器:Serial Old、Parallel Old、CMS;
整堆收集器:G1;
Serial(串行)垃圾收集器是最基本、发展历史最悠久的收集器;
JDK1.3.1前是HotSpot新生代收集的唯一选择;
//特点
针对新生代;
采用复制算法;
单线程收集;
//应用场景
//设置参数
"-XX:+UseSerialGC":添加该参数来显式的使用串行垃圾收集器;
//其他说明
//特点
是Serial的多线程版本。特点和Serival类似。
//应用场景
在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作;
//设置参数
?"-XX:+UseConcMarkSweepGC":指定使用CMS后,会默认使用ParNew作为新生代收集器;
"-XX:+UseParNewGC":强制指定使用ParNew;????
"-XX:ParallelGCThreads":指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同;
//其他说明
为什么只有ParNew能与CMS收集器配合?
CMS是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集线程与用户线程(基本上)同时工作;因为Parallel Scavenge和G1是独立实现的收集器,Parallel Scavenge(以及G1)都没有使用传统的GC收集器代码框架,而其他的收集器都部分使用了框架的代码。
//特点
新生代收集器;
采用复制算法;
多线程收集;
//应用场景
CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间;
而Parallel Scavenge收集器的目标则是达一个可控制的吞吐量(Throughput);
//设置参数
Parallel Scavenge收集器提供两个参数用于精确控制吞吐量:
(A)、"-XX:MaxGCPauseMillis"
??????控制最大垃圾收集停顿时间,大于0的毫秒数;
??????MaxGCPauseMillis设置得稍小,停顿时间可能会缩短,但也可能会使得吞吐量下降;
??????因为可能导致垃圾收集发生得更频繁;
(B)、"-XX:GCTimeRatio"
??????设置垃圾收集时间占总时间的比率,0<n<100的整数;
??????GCTimeRatio相当于设置吞吐量大小;
??????垃圾收集执行时间占应用程序执行时间的比例的计算方法是:
??????1 / (1 + n)
??????例如,选项-XX:GCTimeRatio=19,设置了垃圾收集时间占总时间的5%--1/(1+19);
??????默认值是1%--1/(1+99),即n=99;
(C)、"-XX:+UseAdptiveSizePolicy"
??????开启这个参数后,就不用手工指定一些细节参数,如:
??????新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRation)、晋升老年代的对象年龄(-XX:PretenureSizeThreshold)等;
??????JVM会根据当前系统运行情况收集性能监控信息,动态调整这些参数,以提供最合适的停顿时间或最大的吞吐量,这种调节
?
//其他说明
推荐的设计方式
(1)、只需设置好内存数据大小(如"-Xmx"设置最大堆);
(2)、然后使用"-XX:MaxGCPauseMillis"或"-XX:GCTimeRatio"给JVM设置一个优化目标;
(3)、那些具体细节参数的调节就由JVM自适应完成;
//特点
针对老年代;
采用"标记-整理"算法(还有压缩,Mark-Sweep-Compact);
单线程收集;
//应用场景
主要用于Client模式;
??????而在Server模式有两大用途:
??????(A)、在JDK1.5及之前,与Parallel Scavenge收集器搭配使用(JDK1.6有Parallel Old收集器可搭配);
??????(B)、作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用(后面详解);
//设置参数
?
//其他说明
Parallel Old垃圾收集器是Parallel Scavenge收集器的老年代版本;
JDK1.6中才开始提供;
//特点
针对老年代;
采用"标记-整理"算法;
多线程收集;
//应用场景
JDK1.6及之后用来代替老年代的Serial Old收集器;
特别是在Server模式,多CPU的情况下;
这样在注重吞吐量以及CPU资源敏感的场景,就有了Parallel Scavenge加Parallel Old收集器的"给力"应用组合;
//设置参数
?
"-XX:+UseParallelOldGC":指定使用Parallel Old收集器;
//其他说明
并发标记清理(Concurrent Mark Sweep,CMS)收集器也称为并发低停顿收集器(Concurrent Low Pause Collector)或低延迟(low-latency)垃圾收集器;
//特点
针对老年代;
基于"标记-清除"算法(不进行压缩操作,产生内存碎片);
以获取最短回收停顿时间为目标;
并发收集、低停顿;
需要更多的内存(看后面的缺点);
//应用场景
与用户交互较多的场景;
希望系统停顿时间最短,注重服务的响应速度;
以给用户带来较好的体验;
如常见WEB、B/S系统的服务器上的应用;
//设置参数
?
"-XX:+UseConcMarkSweepGC":指定使用CMS收集器;
//其他说明
G1(Garbage-First)是JDK7-u4才推出商用的收集器;
//特点
(A)、并行与并发
??????能充分利用多CPU、多核环境下的硬件优势;
??????可以并行来缩短"Stop The World"停顿时间;
??????也可以并发让垃圾收集与用户程序同时进行;
(B)、分代收集,收集范围包括新生代和老年代????
??????能独立管理整个GC堆(新生代和老年代),而不需要与其他收集器搭配;
??????能够采用不同方式处理不同时期的对象;
????????????????
??????虽然保留分代概念,但Java堆的内存布局有很大差别;
??????将整个堆划分为多个大小相等的独立区域(Region);
??????新生代和老年代不再是物理隔离,它们都是一部分Region(不需要连续)的集合;
(C)、结合多种垃圾收集算法,空间整合,不产生碎片
??????从整体看,是基于标记-整理算法;
??????从局部(两个Region间)看,是基于复制算法;
??????这是一种类似火车算法的实现;
?
??????都不会产生内存碎片,有利于长时间运行;
(D)、可预测的停顿:低停顿的同时实现高吞吐量
??????G1除了追求低停顿处,还能建立可预测的停顿时间模型;
??????可以明确指定M毫秒时间片内,垃圾收集消耗的时间不超过N毫秒;
//应用场景
?面向服务端应用,针对具有大内存、多处理器的机器;
??????最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案;
??????如:在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒;
????????????
??????用来替换掉JDK1.5中的CMS收集器;
??????在下面的情况时,使用G1可能比CMS好:
??????(1)、超过50%的Java堆被活动数据占用;
??????(2)、对象分配频率或年代提升频率变化很大;
??????(3)、GC停顿时间过长(长于0.5至1秒)。
//设置参数
?
???"-XX:+UseG1GC":指定使用G1收集器;
??????"-XX:InitiatingHeapOccupancyPercent":当整个Java堆的占用率达到参数值时,开始并发标记阶段;默认为45;
??????"-XX:MaxGCPauseMillis":为G1设置暂停时间目标,默认值为200毫秒;
??????"-XX:G1HeapRegionSize":设置每个Region大小,范围1MB到32MB;目标是在最小Java堆时可以拥有约2048个Region;
//其他说明
收集器 串行、并行or并发 新生代/老年代 算法 目标 适用场景
Serial 串行 新生代 复制算法 响应速度优先 单CPU环境下的Client模式
Serial Old 串行 老年代 标记-整理 响应速度优先 单CPU环境下的Client模式、CMS的后备预案
ParNew 并行 新生代 复制算法 响应速度优先 多CPU环境时在Server模式下与CMS配合
Parallel Scavenge 并行 新生代 复制算法 吞吐量优先 在后台运算而不需要太多交互的任务
Parallel Old 并行 老年代 标记-整理 吞吐量优先 在后台运算而不需要太多交互的任务
CMS 并发 老年代 标记-清除 响应速度优先 集中在互联网站或B/S系统服务端上的Java应用
G1 并发 both 标记-整理+复制算法 响应速度优先 面向服务端应用,将来替换CMS
参考连接:
https://segmentfault.com/a/1190000016200996
https://blog.csdn.net/tjiyu/article/details/53983650
标签:min 结果 交换 内存区域 时间片 虚拟 cms 类对象 用户线程
原文地址:https://www.cnblogs.com/codetree/p/12236187.html