15
Java虚拟机是一个进程,因此符合操作系统进程的特征,且是多线程的。整个虚拟机脱离不开操作系统的约束。
java虚拟机运行时运行结构图:
一个进程包含多个线程。有些数据在线程中是共享的。通过new创建出来的对象放在heap中
java虚拟机将内存划分为不同的区域,有些是在java虚拟机启动的时候就存在了,有些事随着线程的生成和销毁而存在的。
perm区是方法区 old+eden+s0+s1 是heap堆区
OOM -OUT OF Memory
1、操作系统的OOM killer
2、java虚拟机中的OOM
2中OOM原理差不多。
//vm参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/root/Documents/javaDump/ import java.util.ArrayList; import java.util.List; public class myjava { static class OOMObject{ } public static void main(String[] args) throws InterruptedException { List<OOMObject> list = new ArrayList<OOMObject>(); while(true){ list.add(new OOMObject()); } } }
运行结果:
java.lang.OutOfMemoryError: Java heap space Dumping heap to /Users/root/Documents/javaDump/java_pid1014.hprof ... Heap dump file created [27569234 bytes in 0.121 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
当内存达到20M会被KILL掉。并且dump到指定目录。
Java虚拟机垃圾回收
1、回收什么?什么可以回收。
以前的方式,查看对象有没有引用。如果没有引用,回收。但是像上图如果5,和6都没有用了,但是他们相互引用。就无法回收。
现在使用左边的图。通过维护一个GC根。所有对象都能到达根,就说明不能回收。如果不能到达根,即使引用不是0,也能回收。就像上图。5,6,7的引用都不是0,但是无法到达根,java虚拟机也会回收。
上面的程序:
每个Arrylist都是存放OOMObject对象。
在while循环中,一直没有执行完。所有的对象一直指向根Arraylist。一直没有被释放掉,所以OOM
如果执行完,就可以被释放。
java虚拟机在OOM之前,进行过多次垃圾回收。只是没有回收完。
-XX:+PrintGC 加一个参数,打印GC信息
[GC (Allocation Failure) 4986K->3457K(19968K), 0.0057425 secs]
[GC (Allocation Failure) 8994K->8000K(19968K), 0.0102037 secs]
[Full GC (Ergonomics) 16797K->12588K(19968K), 0.1313456 secs]
[Full GC (Ergonomics) 16266K->16101K(19968K), 0.1299640 secs]
[Full GC (Allocation Failure) 16101K->16089K(19968K), 0.0809210 secs]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to /Users/root/Documents/javaDump/java_pid1048.hprof ...
Heap dump file created [27569234 bytes in 0.173 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
2、什么时候回收
3、具体如何回收
通过jvisualvm查看java须立即内存堆的更详细的信息
//运行代码 public class mytest { public static void main(String[] args) throws InterruptedException { System.out.println("********************************"); Thread.sleep(1000*60*5); System.out.println("###############################"); } }
元空间 = 方法区
old(老年代)+eden(年轻带)+s0+s1=堆空间。
每部分都有自己的垃圾回收算法
新生成的对象,一般都放在eden和s0。死亡率比较高
一般垃圾回收先在eden区回收,如果经过很多次回收都没有被回收掉,对象就会被移动到old区,有资格进入old区 一般都是长时间都在使用的对象
eden+s0使用频繁,也会频繁的进行回收。死亡率高。采用复制策略。就是把剩下的复制到s1或者复制到old
在老年代采用的回收策略,标记-整理或标记的 清理算法。有些类可以回收了,就先标记。可以死亡了,就进行回收。
指定jc。下图为jdk1.7版本的
这个图,2中算法之间如果没有线连着,表示不能共存。比如年轻带指定parallel Scavenge 那么来年代只能使用serial old或者parallel old 。不能使用cms
Stop the world
-XX:+PrintGCDetails //打印GC详细信息 -XX:+PrintGC //打印GC一般信息
运行第一个程序,打印GC详细信息。运行结果如下:
[GC (Allocation Failure) [PSYoungGen(新生代): 4995K(回收前)->480K(回收后)(6144K)(总大小)] 4995K(回收前整体)->3433K(回收后整体)(19968K)整体堆空间 Xms和Xmx设置的大小, 0.0068095 secs(用时)] [Times: user=0.02(系统用户态使用时间) sys=0.00(系统态), real=0.01(真实感知的时间。比如有3个CPU,每个CPU都占了0.01,那user就是0.03,但是是同时并行的,所以用户感知可能只用了0.015) secs] [GC (Allocation Failure) [PSYoungGen: 6017K->496K(6144K)] 8970K->8000K(19968K), 0.0110276 secs] [Times: user=0.02 sys=0.01, real=0.01 secs] [Full GC (Ergonomics) [PSYoungGen: 6128K->0K(6144K)] [ParOldGen(老年代): 10669K->12588K(13824K)] 16797K->12588K(19968K), [Metaspace(元空间): 2620K->2620K(1056768K)], 0.1348238 secs] [Times: user=0.26 sys=0.00, real=0.14 secs] [Full GC (Ergonomics) [PSYoungGen: 3676K->2488K(6144K)] [ParOldGen: 12588K->13612K(13824K)] 16265K->16101K(19968K), [Metaspace: 2620K->2620K(1056768K)], 0.1376546 secs] [Times: user=0.39 sys=0.01, real=0.14 secs] [Full GC (Allocation Failure) [PSYoungGen: 2488K->2488K(6144K)] [ParOldGen: 13612K->13600K(13824K)(老年代增大)] 16101K->16089K(19968K), [Metaspace: 2620K->2620K(1056768K)], 0.1072099 secs] [Times: user=0.26 sys=0.01, real=0.11 secs] java.lang.OutOfMemoryError: Java heap space Dumping heap to /Users/root/Documents/javaDump/java_pid1444.hprof ... Heap dump file created [27569234 bytes in 0.135 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3210) at java.util.Arrays.copyOf(Arrays.java:3181) at java.util.ArrayList.grow(ArrayList.java:261) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227) at java.util.ArrayList.add(ArrayList.java:458) at myjava.main(myjava.java:11) Heap PSYoungGen total 6144K, used 2711K [0x00000007bf980000, 0x00000007c0000000, 0x00000007c0000000) eden space 5632K, 48% used [0x00000007bf980000,0x00000007bfc25d80,0x00000007bff00000) from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000) to space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000) ParOldGen total 13824K, used 13600K [0x00000007bec00000, 0x00000007bf980000, 0x00000007bf980000) object space 13824K, 98% used [0x00000007bec00000,0x00000007bf9481b0,0x00000007bf980000) Metaspace used 2652K, capacity 4486K, committed 4864K, reserved 1056768K class space used 289K, capacity 386K, committed 512K, reserved 1048576K
Jstat
import java.util.ArrayList; import java.util.List; public class myjava { static class OOMObject{ } public static void main(String[] args) throws InterruptedException { List<OOMObject> list = new ArrayList<OOMObject>(); Thread.sleep(15000); while(true){ list.add(new OOMObject()); } } }
jstat -gc pid 1000(多久打印一次) 20(多少次)
jstat -gc pid 1000(多久打印一次) 20 > a.txt 保存到文件
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
8192.0 8192.0 0.0 0.0 51712.0 2068.5 136704.0 0.0 4480.0 774.4 384.0 75.9 0 0.000 0 0.000 0.000
8192.0 8192.0 0.0 0.0 51712.0 2068.5 136704.0 0.0 4480.0 774.4 384.0 75.9 0 0.000 0 0.000 0.000
C最大大小 U使用
YGC GC次数
YGCT 新生代在垃圾回收里一共占用了多少时间
GCT GC总共暂用多少时间 包括YGC FGC
jstat -gcutil pid 1000 20
jmap
可以用visualVM装入dump文件
jmap -dump:format=b,file=tmm_dump pid
jstat -gc pid 1000 1
jstack -l pid
-XX:+PrintFlagsFinal