其他
面试官:你了解JVM的内存溢出吗?
点击关注下方公众号,编程资料 都在这里
# Java堆溢出
内存溢出:内存空间不足导致,新对象无法分配到足够的内存; 内存泄漏:应该释放的对象没有被释放,多见于自己使用容器保存元素的情况下。
# 示例
-verbose:gc -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
/**
* java 堆内存溢出
* <p>
* VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
*
* @author yuhao.wang3
*/
public class HeapOutOfMemoryErrorTest {
public static void main(String[] args) throws InterruptedException {
// 模拟大容器
List<Object> list = Lists.newArrayList();
for (long i = 1; i > 0; i++) {
list.add(new Object());
if (i % 100_000 == 0) {
System.out.println(Thread.currentThread().getName() + "::" + i);
}
}
}
}
[GC (Allocation Failure) 5596K->1589K(19968K), 0.0422027 secs]
main::100000
main::200000
[GC (Allocation Failure) 7221K->5476K(19968K), 0.0144103 secs]
main::300000
[GC (Allocation Failure) 9190K->9195K(19968K), 0.0098252 secs]
main::400000
main::500000
[Full GC (Ergonomics) 17992K->13471K(19968K), 0.3431052 secs]
main::600000
main::700000
main::800000
[Full GC (Ergonomics) 17127K->16788K(19968K), 0.1581969 secs]
[Full GC (Allocation Failure) 16788K->16758K(19968K), 0.1994445 secs]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:\dump\java_pid7432.hprof ...
Heap dump file created [28774262 bytes in 0.221 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 com.xiaolyuh.HeapOutOfMemoryErrorTest.main(HeapOutOfMemoryErrorTest.java:23)
Disconnected from the target VM, address: '127.0.0.1:61622', transport: 'socket'
1.查询最大对象
2.找出具体的对象
# 解决方案
优化代码,去除大对象; 调整JVM内存大小(-Xmx与-Xms);
# 超出GC开销限制
# 异常栈
[Full GC (Ergonomics) 19225K->19225K(19968K), 0.1044070 secs]
[Full GC (Ergonomics) 19227K->19227K(19968K), 0.0684710 secs]
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to D:\dump\java_pid17556.hprof ...
Heap dump file created [34925385 bytes in 0.132 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
[Full GC (Ergonomics) 19257K->933K(19968K), 0.0403569 secs]
at com.xiaolyuh.HeapOutOfMemoryErrorTest.main(HeapOutOfMemoryErrorTest.java:25)
ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2
JDWP exit error AGENT_ERROR_NO_JNI_ENV(183): [util.c:840]
# 解决方案
通过-XX:-UseGCOverheadLimit参数来禁用这个检查,但是并不能从根本上来解决内存溢出的问题,最后还是会报出java.lang.OutOfMemoryError: Java heap space异常; 调整JVM内存大小(-Xmx与-Xms);
虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
StackOverflowError
单个线程请求的栈深度大于虚拟机所允许的最大深度 创建的线程过多
单个线程请求的栈深度过大
存在递归调用 存在循环依赖调用 方法调用链路很深,比如使用装饰器模式的时候,对已经装饰后的对象再进行装饰
Collections.unmodifiableList(
Collections.unmodifiableList(
Collections.unmodifiableList(
Collections.unmodifiableList(
Collections.unmodifiableList(
...)))))));
/**
* java 虚拟机栈和本地方法栈内存溢出测试
* <p>
* VM Args: -Xss128k
*
* @author yuhao.wang3
*/
public class StackOverflowErrorErrorTest {
private int stackLength = 0;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
StackOverflowErrorErrorTest sof = new StackOverflowErrorErrorTest();
try {
sof.stackLeak();
} catch (Exception e) {
System.out.println(sof.stackLength);
e.printStackTrace();
}
}
}
stackLength::1372
java.lang.StackOverflowError
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
...
stackLength::20641
java.lang.StackOverflowError
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
...
public void stackLeak(String ags1, String ags2, String ags3) {
stackLength++;
stackLeak(ags1, ags2, ags3);
}
stackLength::13154
java.lang.StackOverflowError
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
...
单个线程的栈空间大小(-Xss) 局部变量表的大小
创建的线程过多
虚拟机栈和本地方法栈内存 ≈ 操作系统内存限制 - 最大堆容量(Xmx) - 最大方法区容量(MaxPermSize)
/**
* java 虚拟机栈和本地方法栈内存溢出测试
* <p>
* 创建线程过多导致内存溢出异常
* <p>
* VM Args: -verbose:gc -Xss20M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
*
* @author yuhao.wang3
* @since 2019/11/30 17:09
*/
public class StackOutOfMemoryErrorTest {
private static int threadCount;
public static void main(String[] args) throws Throwable {
try {
while (true) {
threadCount++;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000 * 60 * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
System.out.println("threadCount=" + threadCount);
}
}
}
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at StackOutOfMemoryErrorTest.main(StackOutOfMemoryErrorTest.java:17)
threadCount=4131
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at StackOutOfMemoryErrorTest.main(StackOutOfMemoryErrorTest.java:17)
# 元数据区域的内存溢出
/**
* java 元数据区域/方法区的内存溢出
* <p>
* VM Args JDK 1.6: set JAVA_OPTS=-verbose:gc -XX:PermSize=10m -XX:MaxPermSize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
* <p>
* VM Args JDK 1.8: set JAVA_OPTS=-verbose:gc -Xmx20m -XX:MetaspaceSize=5m -XX:MaxMetaspaceSize=5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
*
* @author yuhao.wang3
*/
public class MethodAreaOutOfMemoryErrorTest {
static class MethodAreaOOM {
}
public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MethodAreaOOM.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] params, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, params);
}
});
enhancer.create();
}
}
}
[GC (Last ditch collection) 1283K->1283K(16384K), 0.0002585 secs]
[Full GC (Last ditch collection) 1283K->1226K(19968K), 0.0075856 secs]
java.lang.OutOfMemoryError: Metaspace
Dumping heap to D:\dump\java_pid18364.hprof ...
Heap dump file created [2479477 bytes in 0.015 secs]
[GC (Metadata GC Threshold) 1450K->1354K(19968K), 0.0003906 secs]
[Full GC (Metadata GC Threshold) 1354K->976K(19968K), 0.0073752 secs]
[GC (Last ditch collection) 976K->976K(19968K), 0.0002921 secs]
[Full GC (Last ditch collection) 976K->973K(19968K), 0.0045243 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:52)
at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at org.springframework.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)
at org.springframework.cglib.core.KeyFactory.create(KeyFactory.java:174)
at org.springframework.cglib.core.KeyFactory.create(KeyFactory.java:153)
at org.springframework.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)
at com.xiaolyuh.MethodAreaOutOfMemoryErrorTest.main(MethodAreaOutOfMemoryErrorTest.java:26)
/**
* java 方法区和运行时常量池溢出
* <p>
* VM Args JDK 1.6: set JAVA_OPTS=-verbose:gc -XX:PermSize10 -XX:MaxPermSize10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
*
* @author yuhao.wang3
*/
public class RuntimeConstantOutOfMemoryErrorTest {
public static void main(String[] args) {
// 使用List保存着常量池的引用,避免Full GC 回收常量池行为
List<String> list = new ArrayList<>();
for (int i = 0; ; i++) {
list.add(String.valueOf(i).intern());
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at RuntimeConstantOutOfMemoryErrorTest.main(RuntimeConstantOutOfMemoryErrorTest.java:18)
/**
* java 直接内存溢出
* <p>
* VM Args JDK 1.6: set JAVA_OPTS=-verbose:gc -Xms20m -XX:MaxDirectMemorySize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
*
* @author yuhao.wang3
*/
public class DirectMemoryOutOfMemoryErrorTest {
public static void main(String[] args) throws IllegalAccessException {
int _1M = 1024 * 1024;
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1M);
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at com.xiaolyuh.DirectMemoryOutOfMemoryErrorTest.main(DirectMemoryOutOfMemoryErrorTest.java:23)
# 解决方案
点个在看你最好看