堆内存OOM是最常见的OOM了。
出现堆内存OOM问题的异常信息如下:
java.lang.OutOfMemoryError: Java heap space
此OOM是由于JVM中heap的最大值,已经不能满足需求了。
举个例子:
@Test public void test01() {
List list = Lists.newArrayList();
while (true) {
list.add(new OOMTests());
}
}
这里创建了一个list集合,在一个死循环中不停往里面添加对象。
执行结果:
出现了java.lang.OutOfMemoryError: Java heap space的堆内存溢出。
很多时候,excel一次导出大量的数据,获取在程序中一次性查询的数据太多,都可能会出现这种OOM问题。
我们在日常工作中一定要避免这种情况。
有时候,我们的业务系统创建了太多的线程,可能会导致栈内存OOM。
出现堆内存OOM问题的异常信息如下:
java.lang.OutOfMemoryError: unable to create new native thread
举个例子
public class StackOOMTest {
public static void main(String[] args) {
while (true) {
new Thread().start();
}
}
}
使用一个死循环不停创建线程,导致系统产生了大量的线程。
如果实际工作中,出现这个问题,一般是由于创建的线程太多,或者设置的单个线程占用内存空间太大导致的。
建议在日常工作中,多用线程池,少自己创建线程,防止出现这个OOM。
我们在业务代码中可能会经常写一些 递归调用,如果递归的深度超过了JVM允许的最大深度,可能会出现栈内存溢出问 题。
出现栈内存溢出问题的异常信息如下:
java.lang.StackOverflowError
举个例子
@Test
public void test03() {
recursiveMethod();
}
public static void recursiveMethod() {
// 递归调用自身
recursiveMethod();
}
出现了java.lang.StackOverflowError栈溢出的错误。
我们在写递归代码时,一定要考虑递归深度。即使是使用 parentId一层层往上找的逻辑,也最好加一个参数控制递归 深度。防止因为数据问题导致无限递归的情况,比如:id和 parentId的值相等。
直接内存不是虚拟机运行时数据区的一部分,也不是《Java 虚拟机规范》中定义的内存区域。
它来源于 NIO ,通过存在堆中的 DirectByteBuffer 操作 Native内存,是属于堆外内存 ,可以直接向系统申请的内存空间。 出现直接内存OOM问题时异常信息如下:
java.lang.OutOfMemoryError: Direct buffer memory
例如:
private static final int BUFFER = 1024 * 1024 * 20;
@Test
public void test04() {
ArrayList list = new ArrayList();
int count = 0;
try {
while (true) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
会看到报出来java.lang.OutOfMemoryError: Direct buffer memory直接内存空间不足的异常。
GC OOM 是由于JVM在GC时,对象过多,导致内存溢出,建 议调整GC的策略。 出现GC OOM问题时异常信息如下:
java.lang.OutOfMemoryError: GC overhead limit exceeded
为了方便测试,我先将idea中的最大和最小堆大小都设置成 10M,例如下面这个例子:
public class GCOverheadOOM {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
});
}
}
}
出现这个问题是由于JVM在GC的时候,对象太多,就会报这 个错误。 我们需要改变GC的策略。 在老代80%时就是开始GC,并且将-XX:SurvivorRatio(- XX:SurvivorRatio=8)和-XX:NewRatio(- XX:NewRatio=4)设置的更合理。
JDK8 之后使用 Metaspace 来代替 永久代 ,Metaspace是方 法区在 HotSpot 中的实现。
Metaspace不在虚拟机内存中,而是使用本地内存也就是在 JDK8中的 ClassMetadata ,被存储在叫做Metaspace的 native memory。
出现元空间OOM问题时异常信息如下:
java.lang.OutOfMemoryError: Metaspace
为了方便测试,我们修改一下idea中的JVM参数,增加下面的配 置:
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
指定了元空间和最大元空间都是10M。 接下来,看看下面这个例子:
public class MetaspaceOOMTest {
static class OOM {
}
public static void main(String[] args) {
int i = 0;
try {
while (true) {
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOM.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[]
return methodProxy.invokeSuper(o, args);
}
});
enhancer.create();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
程序最后会报java.lang.OutOfMemoryError: Metaspace的 元空间OOM。 这个问题一般是由于加载到内存中的类太多,或者类的体积太 大导致的。
在Java中,发生了OutOfMemoryError(OOM)不一定会导致整个JVM退出。是否退出取决于发生OOM错误的线程和错误处理逻辑。这是一个复杂的问题,具体行为会因应用程序实现方式、错误发生的情境以及错误处理策略而异。
注意:
分别是最短暂停时间和高吞吐量
针对最短暂停时间和高吞吐举个例子:
两个方案相对而言第一个时延低,第二个吞吐高,基本上两者不可兼得。所以调优时候需要明确应用的目标。
GC调优这种问题肯定是具体场景具体分析,但是在面试中就不要讲太细,大方向说清楚就行,不需要涉及具体的垃圾收集器比如 CMS 调什么参数,G1 调什么参数之类的。
GC 调优的核心思路就是尽可能的使对象在年轻代被回收,减少对象进入老年代。
具体调优还是得看场景根据 GC日志具体分析,常见的需要关注的指标是 Young GC 和 Ful GC 触发频率、原因、晋升的速率、老年代内存占用量等等。比加发现频繁产生FullGC,分析日志之后发现没有内存泄漏,只是 Young GC之后会有大量的对象进入老年代,然后最终触发FullGC,所以就能得知是 Survivor 空间设置太小,导致对象过早进入老年代,因此调大Survivor。或者是晋升年龄设置的太小,也有可能分析日志之后发现是内存泄漏、或者有第三方类库调用了 System.gc 等等。反正具体场景具体分析,核心思想就是尽量在新生代把对象给回收了,
基本上这样说就行了,然后就等着面试官延伸了
记住前两个,其它的使用时再查就行
JVM(Java虚拟机)的启动参数用于配置和调整Java应用程序的运行时行为。以下是一些常用的JVM启动参数:
这些是一些常见的JVM启动参数,可以根据应用程序的需求和性能调优的目标进行调整。JVM启动参数的使用可以显著影响应用程序的性能和行为,因此在设置这些参数时需要谨慎。同时,JVM支持的启动参数因不同的JVM版本和供应商而有所不同,建议查阅相关文档以获取更详细的信息。
先确认是否真的发生了内存泄漏,即观察内存使用情况。
利用 jstat 命令(jstat -gc
)来观察 gc 概要信息,如果发现,GC 后内存并没有明显的减少目还是持续增加持续触发gc,那说明内存泄漏的概率很大。
此时可以利用 jmap(jmap -dump:format=b,fi1e=heapdump.hprof
)生成 heap dump,然后将其导入 Ecdipse MAT 或者 VsuaVM 工具内进行分析,通过大量内存的占用可以找到对应的对象。
通过对象找到对应的代码分析,确认是否可能存在内存泄漏的场景,最终修复代码,解决内存泄漏的问题。
本文来自在线网站:seven的菜鸟成长之路,作者:seven,转载请注明原文链接:www.seven97.top
参与评论
手机查看
返回顶部