-
java内存区域划分
在java8,将方法区替代为元空间(由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出)
-
发生fullgc的情况有哪些
第一:是老年代可用内存小于新生代全部对象的大小,如果没开启空间担保参数,会直接触发Full GC,所以一般空间担保参数都会打开;注:jDK1.8之后已经取消了-XX:-HandlePromotionFailure
机制
第二:是老年代可用内存小于历次新生代GC后进入老年代的平均对象大小,此时会提前Full GC;
第三:是新生代Minor GC后的存活对象大于Survivor,那么就会进入老年代,此时老年代内存不足。
上述情况都会导致老年代Full GC。
第四:就是“-XX:CMSInitiatingOccupancyFaction”参数,
如果老年代可用内存大于历次新生代GC后进入老年代的对象平均大小,但是老年代已经使用的内存空间超过了这个参数指定的比例,也会自动触发Full GC。默认92%
-
发生oom的情况有哪些?哪些区域可能会发生oom
内存溢出通俗的讲就是内存不够用了,并且 GC 通过垃圾回收也无法提供更多的内存。(1)堆溢出:heap (2)栈溢出:stack (3)元空间溢出:Metaspace
实际上除了程序计数器,其他区域都有可能发生 OOM, 简单总结如下:
-
堆内存不足是最常见的 OOM 原因之一,抛出错误信息
java.lang.OutOfMemoryError:Java heap space
,原因也不尽相同,可能是内存泄漏,也有可能是堆的大小设置不合理。 -
对于虚拟机栈和本地方法栈,导致 OOM 一般为对方法自身不断的递归调用,且没有结束点,导致不断的压栈操作。类似这种情况,JVM 实际会抛出
StackOverFlowError
, 但是如果 JVM 试图去拓展栈空间的时候,就会抛出 OOM. -
对于老版的 JDK, 因为永久代大小是有限的,并且 JVM 对老年代的内存回收非常不积极,所以当我们添加新的对象,老年代发生 OOM 的情况也非常常见。
-
随着元数据区的引入,方法区内存已经不再那么窘迫,所以相应的 OOM 有所改观,出现 OOM,异常信息则变成了:“java.lang.OutOfMemoryError: Metaspace”。
-
OOM怎么排查的?
https://blog.csdn.net/fishinhouse/article/details/80781673
-
new对象时会在哪个区域分配
1)依据逃逸分析,判断是否能栈上分配?
如果可以,使用标量替换方式,把对象分配到VM Stack
中。如果 线程销毁或方法调用结束后,自动销毁,不需要 GC 回收器 介入。
否则,继续下一步。
2)判断是否大对象?
如果是,直接分配到堆上 Old Generation
老年代上。如果对象变为垃圾后,由老年代GC 收集器(比如 Parallel Old, CMS, G1)回收。
否则,继续下一步。
3)判断是否可以在 TLAB
中分配?
如果是,在 TLAB
中分配堆上Eden
区。
否则,在 TLAB
外堆上的Eden
区分配。
TLAB,全称Thread Local Allocation Buffer, 即:线程本地分配缓存。这是一块线程专用的内存分配区域。
TLAB占用的是eden区的空间。
在TLAB启用的情况下(默认开启),JVM会为每一个线程分配一块TLAB区域。
为什么需要TLAB?这是为了加速对象的分配。
由于对象一般分配在堆上,而堆是线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,会使分配的效率下降。
考虑到对象分配几乎是Java中最常用的操作,因此JVM使用了TLAB这样的线程专有区域来避免多线程冲突,提高对象分配的效率。
局限性: TLAB空间一般不会太大(占用eden区),所以大对象无法进行
TLAB
分配,只能直接分配到堆Heap
上。