文章目录

1. pom
<!--动态生成class文件-->
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2. MemoryController
package com.gblfy.chapter2;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@RestController
public class MemoryController {


private List<User> userList = new ArrayList<User>();
private List<Class<?>> classList = new ArrayList<Class<?>>();


/**
* 构造堆内存溢出
* 最大内存: -Xmx32M
* 最小内存: -Xms32M
* -Xmx32M -Xms32M
*/
@RequestMapping("/heap")
public void heap() {
int i = 0;
while (true) {
userList.add(new User(i++, UUID.randomUUID().toString()));
}
}
/**
* 构造非堆内存溢出
* 最大Metaspace: -XX:MaxMetaspaceSize=32M
* 最小Metaspace: -XX:MetaspaceSize=32M
* -XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M
*/
@RequestMapping("/noheap")
public void noheap() {
while (true) {
classList.addAll(Metaspace.createClasses());
}
}
}
3. User 对象
package com.gblfy.chapter2;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {

private int id;
private String name;
}
4. 动态生成class文件工具类
package com.gblfy.chapter2;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/*
* 继承ClassLoader是为了方便调用defineClass方法,因为该方法的定义为protected
* */
public class Metaspace extends ClassLoader {

public static List<Class<?>> createClasses() {
// 类持有
List<Class<?>> classes = new ArrayList<Class<?>>();
// 循环1000w次生成1000w个不同的类。
for (int i = 0; i < 10000000; ++i) {
ClassWriter cw = new ClassWriter(0);
// 定义一个类名称为Class{i},它的访问域为public,父类为java.lang.Object,不实现任何接口
cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null,
"java/lang/Object", null);
// 定义构造函数<init>方法
MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
"()V", null, null);
// 第一个指令为加载this
mw.visitVarInsn(Opcodes.ALOAD, 0);
// 第二个指令为调用父类Object的构造函数
mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
"<init>", "()V");
// 第三条指令为return
mw.visitInsn(Opcodes.RETURN);
mw.visitMaxs(1, 1);
mw.visitEnd();
Metaspace test = new Metaspace();
byte[] code = cw.toByteArray();
// 定义类
Class<?>
5. 启动项目

为了方便快速模拟,需要设置堆内存参数

JVM调优_堆内存溢出和非堆内存溢出_java

JVM调优_堆内存溢出和非堆内存溢出_spring_02

6. 测试连接
测试堆内存溢出链接:
http://localhost/heap

测试非堆内存溢出链接:
http://localhost/noheap
7. 异常信息

JVM调优_堆内存溢出和非堆内存溢出_内存溢出_03

JVM调优_堆内存溢出和非堆内存溢出_内存溢出_04