继上文:深入方法区
java堆,属于内存中最大的一块,也是常见OOM发生地,大部分对象的实例都是在这里分配内存,当然随着逃逸分析技术的日益强大,栈上分配、标量替换也是可以直接分配对象内存的,所以不是所有的java实例都是在堆中分配。
java堆的内存结构是什么?
注意以上是1.8及以上的版本内存结构,jdk1.8以前是永久代。
堆空间有:年轻代、老年代、元空间
年轻代分为伊甸元区(Eden)和Survivor区(幸存区) 点整个堆空间的 1/3;
伊甸元区(Eden)
Survivor区又分为:S0(from)、S1(to)
edn:S0:S1之间的比例是:8:1:1
老年代占整个堆空间的 2/3
元空间属于堆外空间也是方法区;
几种垃圾回收的区别?
年轻代发生的GC叫Minor GC,老年代发生的GC叫Major GC,Full GC是清理整个空间包括年轻代和老年代;
Minor GC
若发现edn空间已满,则进行Minor GC,通过可达性算法分析,将垃圾对象进行回收edn和Survivor 0,然而如果不是垃圾会被移入Survivor 1,当下次edn又满了,那会将 edn及Survivor1 进行回收,把不是垃圾放到Survivor 0也就是说每次会将Survivor 中一个进行回收将不回收放到另一个Survivor。
当某个对象回收次性达15次(jvm默认),会自动放到老年代中。
Major GC
Major GC这个是不确定的,在oracle或相关资料了解发现,这个Major GC触发前至少会触发一次Minor GC并且这个Major GC比Minor GC慢10倍。
Full GC
手动调用Sytem.GC()
老年代空间不足时
GC担保失败
Full GC这个触发一般触发条件是,手动调用、老年代最大可用空间小于现在新生代对象空间,还有担保空间发现不足,这几种都需要进行Full GC。
注意:不管内存怎么收,只是将某个位置标记为可用,新的对象直接覆盖原来的位置,而不是真的把对象清掉,回收只是将空闲表上面标记为可用。
(以上图来自互联网)
JVM参数配置
参数 描述
-Xms: | 堆内存初始大小 |
---|---|
-Xmx: | MaxHeapSize设置堆的最大空间大小 |
-Xmn: | 设置年轻代大小 |
-XX:NewSize(-Xns) | 年轻代内存初始大小 |
-XX:MaxNewSize(-Xmn) | 设置新生代最大空间大小方法区 |
-XX:NewRatio | 新生代和老年代的比值,值为4新生代:老年代=1:4,即年轻代占堆的1/5 |
-XX:SurvivorRatio=8 | 年轻代中Eden区与Survivor区的容量比例值,默认为8 |
-XX:+HeapDumpOnOutOfMemoryError | 内存溢出时,导出堆信息到文件 |
-XX:+HeapDumpPath | 堆Dump路径 |
-XX:OnOutOfMemoryError | 当发生OOM内存溢出时,执行一个脚本 |
-XX:MaxTenuringThreshold=7 | 表示如果在幸存区移动多少次没有被垃圾回收,进入老年代 |
TLAB是什么?
TLAB全称Thread Local Allocation Buffer,中文名称是:本地线程缓存区,主要的作用是专门用来分配内存避免多线程间的冲突,这个TLAB是在eden中的占1%,当分配对象的时候先尝试栈上分配,不成功则继续TLAB分配,不成功则直接进入老年代。
java堆是连续的吗?
java堆理论上是连续的,但是官方给出来的说法是非连续的,整体是连续,但是存在不连续的地方。
模拟内存溢出实例
如果计算需要的堆多于自动存储管理系统可以提供的堆,则Java虚拟机将抛出一个 OutOfMemoryError。
/**
*
* 功能描述: 测试OOM的问题
* -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails
*
* @param:
* @return:
* @auther: csh
* @date: 2020/12/3 15:01
*/
public class OOME {
static class OOMObject {
}
public static void main(String args[]) {
List <OOMObject> list = new ArrayList <OOMObject>();
while (true) {
list.add(new OOMObject());
}
}
}
[GC (Allocation Failure) [PSYoungGen: 5101K->488K(6144K)] 5101K->2836K(19968K), 0.0030660 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 6120K->480K(6144K)] 8468K->6979K(19968K), 0.0058824 secs] [Times: user=0.08 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) [PSYoungGen: 6112K->488K(6144K)] 12611K->12594K(19968K), 0.0073455 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[Full GC (Ergonomics) [PSYoungGen: 488K->0K(6144K)] [ParOldGen: 12105K->10620K(13824K)] 12594K->10620K(19968K), [Metaspace: 3450K->3450K(1056768K)], 0.1760388 secs] [Times: user=0.39 sys=0.00, real=0.18 secs]
[Full GC (Ergonomics) [PSYoungGen: 5632K->511K(6144K)] [ParOldGen: 10620K->13627K(13824K)] 16252K->14139K(19968K), [Metaspace: 3450K->3450K(1056768K)], 0.1199610 secs] [Times: user=0.44 sys=0.00, real=0.12 secs]
[Full GC (Ergonomics) [PSYoungGen: 3063K->2857K(6144K)] [ParOldGen: 13627K->13627K(13824K)] 16690K->16484K(19968K), [Metaspace: 3450K->3450K(1056768K)], 0.1521509 secs] [Times: user=0.75 sys=0.01, real=0.15 secs]
[Full GC (Allocation Failure) [PSYoungGen: 2857K->2857K(6144K)] [ParOldGen: 13627K->13609K(13824K)] 16484K->16466K(19968K), [Metaspace: 3450K->3450K(1056768K)], 0.1254353 secs] [Times: user=0.56 sys=0.02, real=0.13 secs]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid9668.hprof ...
Heap dump file created [28238817 bytes in 0.089 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:265)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
at java.util.ArrayList.add(ArrayList.java:462)
at com.jvm.oom.OOME.main(OOME.java:23)
Heap
PSYoungGen total 6144K, used 3016K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)
eden space 5632K, 53% used [0x00000000ff980000,0x00000000ffc72028,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 13824K, used 13609K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)
object space 13824K, 98% used [0x00000000fec00000,0x00000000ff94a580,0x00000000ff980000)
Metaspace used 3482K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 379K, capacity 388K, committed 512K, reserved 1048576K
从上列可以看出,先经过三次PSYoungGen,也就是所说的Minor GC,然后再经历过多次Full GC ,最后内存溢出。
最后
由于堆中的东西实在太多了,本文算是一个基础入门后需到内存和垃圾回收到重点深入,并且可结合各种场景来深入更好。
参考文章:
https://www.cnblogs.com/nyhhd/p/12641370.html
系列文章:
...