黑马程序员《JVM完整教程》笔记 - p015 - p026
b站链接: 黑马程序员JVM完整教程
本地方法栈
native方法:不是本地创建的方法。
本地方法栈的作用:给本地方法的运行提供一个内存空间。
堆
定义
Heap 堆
- 通过new关键字,创建对象都会使用堆内存
特点
- 它是线程共享的,堆中对象都需要考虑线程安全的问题
- 有垃圾回收机制(堆中不再被引用的对象都需要考虑线程安全问题)
堆内存溢出
VM options -Xmx8m 修改堆空间为8M
内存空间调小,较容易暴露出堆内存的问题
堆内存诊断
- jps工具
- 查看当前系统中有哪些java进程 - jmap工具
- 查看某一时刻堆内存占用情况 -heap 进程id - jconsole工具
- 图形界面的,多功能的监测工具,可以连续监测
public class Demo1_1 {
public static void main(String[] args) throws InterruptedException {
System.out.println("1...");
Thread.sleep(30000);
byte[] array = new byte[1024 * 1024 * 10]; // 10 Mb
System.out.println("2...");
Thread.sleep(30000);
array = null;
System.gc();
System.out.println("3...");
Thread.sleep(1000000L);
}
}
使用jmap监测堆占用情况,在三个时间点抓取内存快照信息
格式:jmap -heap 进程id
获取到堆的配置信息
Eden – 新创建的对象的区域
案例:垃圾回收后,内存占用仍然很高
E:\git\jvm\out\production\jvm\cn\itcast\jvm\t1>jps
E:\git\jvm\out\production\jvm\cn\itcast\jvm\t1>jmap -heap 17748
发现老年代未被回收,使用jvisualvm,监测内存占用,可以执行垃圾回收。
E:\git\jvm\out\production\jvm\cn\itcast\jvm\t1>jvisualvm
堆 Dump
找到问题部分,点开后逐步搜索,找到问题具体位置。
方法区
定义
- 方法区是所有Java虚拟机线程的一个共享区域,存储了跟类的结构相关的一些信息。主要包括:运行时常量池,方法,构造器,成员方法。
- 方法区在虚拟机启东时被创建,逻辑上是堆的一个组成部分。具体实现上不同的jvm厂商实现时各不相同,并不强制方法区的位置。
- 方法区在运行时如果内存不足,也会抛出OutOfMemoryError。
本地内存:操作系统内存
方法区内存溢出
- 1.8以前会导致永久代内存溢出
- 1.8以后会导致元空间内存溢出
/**
* 演示元空间内存溢出
* -XX:MaxMetaspaceSize=8m
*/
public class Demo1_2 extends ClassLoader { // 可以用来加载类的二进制字节码
public static void main(String[] args){
int j = 0;
try {
Demo1_8 test = new Demo1_8();
for (int i = 0; i < 10000; i++, j++) {
// ClassWriter 作用是生成类的二进制字节码
ClassWriter cw = new ClassWriter(0);
// 版本号,public,类名,包名,父类,接口
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);
// 返回 byte[]
byte[] code = cw.toByteArray();
// 执行了类的加载
test.defineClass("Class" + i, code, 0, code.length);
}
} finally {
System.ou.println(j);
}
}
}
元空间内存溢出:Metaspace
永久代内存溢出:PermGen space
场景
- spring
- mybatis
常量池
// 二进制字节码(类基本信息,常量池,类方法定义包含了虚拟机指令)
public class HelloWorld {
public static void main(String[] args){
System.out.println("hello world");
}
}
E:\git\jvm\out\production\cn\itcast\jvm\t5>javap -v HelloWorld.class
-v 操作显示反编译后的详细信息
运行时常量池
- 常量池,就是一张表,虚拟机指令根据这张表找到要执行的类名,方法名,参数类型,自变量等信息
- 运行时常量池,常量池是 *.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址