GC
频繁收集Young区,较少收集Old区,基本不动Perm区
jdk1.7
新生代:-Xmn
新生代+旧生代:-Xms -Xmx
永久代:-XX:PermSize,-XX:MaxPermSize
jdk1.8
jdk1.8之后将最初的永久代取消,由元空间取代
目的:将HotSpot与Rockit两个虚拟机的标准整合
堆内存调优
- -Xms
- 设置初始内存大小,默认为物理内存的1/64
- -Xmx
- 最大分配内存,默认为物理内存的1/4
- -XX:+PrintGCDetails
- 输出详细的GC处理日志
package top.ygy.jvm;
/**
* @Description: TODO(这里用一句话描述这个类的作用)
* @author yangguangyuan
* @date 2019年6月27日 -Xmx1024m -Xms1024m -XX:+PrintGCDetails
*/
public class StackDemo2 {
public static void main(String[] args) {
long maxMemory = Runtime.getRuntime().maxMemory();// java虚拟机(这个进程)能构从操作系统那里挖到的最大的内存
long totalMemory = Runtime.getRuntime().totalMemory();// java虚拟机这个进程当时所占用的所有内存
System.out.println("maxMemory=" + maxMemory + "字节 "
+ maxMemory / (double) 1024 / 1024 + "MB");
System.out.println("totalMemory=" + totalMemory + "字节 "
+ totalMemory / (double) 1024 / 1024 + "MB");
}
}
自动触发垃圾回收
若养老区执行了Full GC后发现依然无法进行对象的保存,就回产生OOM异常,
package top.ygy.jvm;
import java.util.Random;
/**
* @Description: TODO(这里用一句话描述这个类的作用)
* @author yangguangyuan
* @date 2019年6月27日
* -Xmx1m -Xms1m -XX:+PrintGCDetails
*/
public class StackDemo3 {
public static void main(String[] args) {
String str = "ceshiceshiceshiceshiceshi";
while(true) {
str = str+new Random().nextInt(8888888)+new Random().nextInt(9999999);
}
}
}
结果:
[Full GC (Ergonomics) [PSYoungGen: 364K->361K(1024K)] [ParOldGen: 492K->492K(512K)] 857K->853K(1536K), [Metaspace: 2834K->2834K(1056768K)], 0.0045862 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 361K->361K(1024K)] [ParOldGen: 492K->492K(512K)] 853K->853K(1536K), [Metaspace: 2834K->2834K(1056768K)], 0.0048538 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
Exception in thread "main" Heap
PSYoungGen total 1024K, used 379K [0x00000000ffe80000, 0x0000000100000000, 0x0000000100000000)
eden space 512K, 74% used [0x00000000ffe80000,0x00000000ffededc8,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 512K, used 492K [0x00000000ffe00000, 0x00000000ffe80000, 0x00000000ffe80000)
object space 512K, 96% used [0x00000000ffe00000,0x00000000ffe7b308,0x00000000ffe80000)
Metaspace used 2866K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 304K, capacity 386K, committed 512K, reserved 1048576K
java.lang.OutOfMemoryError: Java heap space
GC三大算法
JVM在进行GC时,并非每次都对三个内存区域一起回收,大部分回收的都是指新生代,因此GC按照回收的区域又分为两种类型,一种是普通GC(minor GC),一种是全局GC(major GC or Full GC).
- 普通GC:只针对新生代区域GC
- 全局GC:针对旧生代GC,偶尔伴随对新生代的GC以及对永久代的GC
复制算法
优势劣势
- 优点
- 不会产生内存碎片,完整度极高
- 缺点
- 浪费一半空间,总要有50%是to区域
- 如果对象存活率很高,花费时间多,所以需要对象存活率很低,而且必须克服50%的内存浪费
使用场景
Minor GC(普通GC)
- 年轻代中使用的是minor GC,这种GC算法采用的是复制算法(Copying)
组成部分
我们首先一起来看一下复制算法的做法,复制算法将内存划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的。
当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。接下来GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。
此时,空闲区间已经与活动区间交换,而垃圾对象现在已经全部留在了原来的活动区间,也就是现在的空闲区间。事实上,在活动区间转换为空间区间的同时,垃圾对象已经被一次性全部回收。
标记清除
优势劣势
- 优点
- 不需要额外空间
- 缺点
- 两次扫描,耗时严重
- 会产生内存碎片
使用场景
旧生代一般是由标记清除或者标记清除与标记整理的混合实现
组成部分
Mark-Sweep,Full GC,标记清除是标记死的
- 标记:从根集合开始扫描,对存活的对象进行标记
- 清除:扫描整个内存空间,回收未被标记的对象,使用free-list记录可以区域
标记整理
优势劣势
- 优点
- 不会产生内存碎片
- 缺点
- 效率不高,不仅要标记存活的对象,还要整理所有存活对象的引用地址
- 从效率上说,标记整理算法要低于复制算法
使用场景
旧生代一般是由标记清除或者标记清除与标记整理的混合实现
组成部分
Mark-Compact,Full GC,标记整理是标记活的
相似对比
- 内存效率:复制算法>标记清除算法>标记整理算法(简单的时间复杂度对比)
- 内存整齐度:复制算法=标记整理算法>标记清除算法
- 内存利用率:标记整理算法=标记清除算法>复制算法