网站首页 > 技术文章 正文
Java堆溢出
Java堆用于存储对象实例,只要不断创建对象,保证GC Roots到对象间有可达路径避免垃圾回收机制清除这些对象
package cn.pengld;
import java.util.ArrayList;
import java.util.List;
/**
* VM Args: -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
*/
public class HeapSpaceOOMTest {
static class OOMObject{}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<>();
while (true){
list.add(new OOMObject());
}
}
}
虚拟机栈和本地方法栈溢出
由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,所以栈容量只由-Xss参数设定。在单个线程下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,虚拟机抛出的都是 StackOverflowError 异常。
当不限于单线程时,通过不断创建线程的方式可以产生内存溢出异常。
package cn.pengld;
/**
* VM Args: -Xss2M
*/
public class StackSpaceOOMTest {
private void keepGoing(){
while (true){
}
}
public void stackLeakByThread(){
while (true){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
keepGoing();
}
});
thread.start();
}
}
public static void main(String[] args) {
StackSpaceOOMTest stackSpaceOOMTest = new StackSpaceOOMTest();
stackSpaceOOMTest.stackLeakByThread();
}
}
运行时常量池溢出(方法区的一部分)
String类是被final修饰的不可变类,更不能被继承,这样做的目的是为了性能,程序大部分的操作是针对字符串的,将字符串放在常量池中,能有效提高程序运行的效率。若大量的创建字符串对象,会导致常量池内存不够,导致常量池OOM,这也是在处理字符串拼接时使用 StringBuilder对象替代的原因。
package cn.pengld;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ConstantPoolOOMTest {
/**
* -XX:PermSize=10M -XX:MaxPermSize=10M JDK版本号小于 1.7
* Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
*/
public static void jdk6(){
// 保持GC Roots的引用链,避免GC被回收
List<String> list = new ArrayList<>();
int i = 0;
while (true){
list.add(String.valueOf(i++).intern());
}
}
/**
*
* 自JDK 7起,原本存放在永久代的字符串常量池被移至Java堆之中
* VM Args: -Xmx6M
*/
public static void jdk7up(){
// 保持GC Roots的引用链,避免GC被回收
Set<String> list = new HashSet<>();
short i = 0;
while (true){
list.add(String.valueOf(i++).intern());
}
}
public static void main(String[] args) {
// use 1.6
// jdk6();
// use 7+
jdk7up();
}
}
特别说明:笔者还原了此种情况,运行很多次OOM都发生在HashMap的resize()方法时,但具体的OOM异常取决于具体哪里的对象分配时发生了溢出。参照 《深入理解Java虚拟机:JVM高级特性与最佳实践》(周志明)第三版 2.4.3章节
方法区溢出
方法区的主要职责是用于存放类型的相关信息,如类 名、访问修饰符、常量池、字段描述、方法描述等。基本的思路是运行时产 生大量的类去填满方法区,直到溢出为止。不过在JDK 8以后,永久代便完全退出了历史舞台,元空间作为其替代者登场。
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removed in 8.0
下面演示在JDK1.6时如何制造方法区OOM。
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
package cn.pengld;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 借助CGLib使得方法区出现内存溢出异常 jdk 1.6
* VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
*/
public class MethodAreaOOMTest {
public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}
static class OOMObject {
}
}
本机直接内存溢出
参照《深入理解Java虚拟机-JVM高级特性与最佳实践》(周志明)第二版 2.4.4
package cn.pengld;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
/**
* VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
*/
public class DirectMemoryOOMTest {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
unsafe.allocateMemory(_1MB);
} }
}
Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at org.fenixsoft.oom.DMOOM.main(DMOOM.java:20)
猜你喜欢
- 2024-10-12 SpringBoot执行jar报错java.lang.OutOfMemoryError_指定内存大小
- 2024-10-12 几种内存溢出(内存溢出类型)
- 2024-10-12 JVM优化:实战OutOfMemoryError异常
- 2024-10-12 JVM 在遇到OOM(OutOfMemoryError)时生成Dump文件的三种方式
- 2024-10-12 线上故障排查全套路,总有一款适合你
- 2024-10-12 面试被问到“零拷贝”!你真的理解吗?
- 2024-10-12 面试夺命三问之《内存溢出和逃逸分析》
- 2024-10-12 阿里面试官:Exception和Error有什么区别?
- 2024-10-12 Eclipse运行大量文件异常OutOfMemoryError: GC overhead limit
- 2024-10-12 记一次线上内存异常排查实战(线上内存泄漏如何定位)
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)