- jmap工具
// jmap用于查看当前系统中堆内存占用情况(静态形式)// 我们直接在IDEA的输入台输入即可jmap -heap 进程id// 我们可以看到Heap Usage就是内存管理// 其中Eden space 为新产生的堆内存// 其中Old Generation 为之前产生的堆内存
- jconsole工具
// jconsole用于查看当前系统中堆内存占用情况(图形化界面app展示)// 我们直接在IDEA的输入台输入即可jconsole
- jvisualvm工具
// jvisualvm用于查看当前系统中堆内存占用情况(图形化界面app展示)// 我们直接在IDEA的输入台输入即可jvisualvm
方法区这小节我们来介绍JVM内存结构中的方法区方法区简介我们首先来简单介绍一下方法区:
- 方法区是所有java虚拟机共享的一片区域
- 方法区中存放着所有类的所有信息 , 包括有属性 , 方法,构造方法等
- 方法区在虚拟机启动的一瞬间被创建,同样在虚拟机停止时方法区进行销毁
- 方法区和程序计数器一样只是一个概念
- 我们在实际开发中,jdk1.8之前采用的是永久代,在jdk1.8及以后均采用元空间

文章插图
方法区内存溢出问题方法区同样存在有内存溢出问题,但并不常见
我们将方法区的讲解分为两部分,有永久代也有元空间的讲解:
- 永久代内存溢出问题
// 永久代的概念仅存在于jdk1.8之前,我们可以通过-XX来控制永久代大小// 当方法区为永久代时,溢出就显示错误java.lang.OutOfMemoryError: PermGen spacepackage cn.itcast.jvm;import com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter;import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes;/** * 演示永久代内存溢出java.lang.OutOfMemoryError: PermGen space * -XX:MaxPermSize=8m */public class Demo1_8 extends ClassLoader {public static void main(String[] args) {int j = 0;try {Demo1_8 test = new Demo1_8();for (int i = 0; i < 20000; i++, j++) {ClassWriter cw = new ClassWriter(0);cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);byte[] code = cw.toByteArray();test.defineClass("Class" + i, code, 0, code.length);}} finally {System.out.println(j);}}}
- 元空间内存溢出问题
// 元空间存在于jdk1.8之后,实际上这时的元空间已经作用于系统内存了 , 相当于元空间的大小几乎是不可能出现溢出的// 所以我们需要先设置元空间大小才能观察到溢出问题:-XX:MaxMetaspaceSize=8m// 当方法区为永久代时,溢出就显示错误java.lang.OutOfMemoryError: Metaspacepackage cn.itcast.jvm.t1.metaspace;import jdk.internal.org.objectweb.asm.ClassWriter;import jdk.internal.org.objectweb.asm.Opcodes;/** * 演示元空间内存溢出 java.lang.OutOfMemoryError: Metaspace * -XX:MaxMetaspaceSize=8m */public class Demo1_8 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); // Class 对象}} finally {System.out.println(j);}}}
常量池简介我们再回到方法区来简单介绍一下常量池:- 我们在上面的图中可以看到常量池之前是放在方法区中的StringTable,但在jdk1.8之后放在了堆中的StingTable
- 我们需要注意的是:即使StringTable在堆里面,在堆里存放的数据和在StringTable里存放的数据也不是同一个数据
- 常量池实际上是一张表
- 虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
- 运行时常量池,常量池是 *.class 文件中的
- 当该类被加载,它的常量池信息就会放入运行时常量池 , 并把里面的符号地址变为真实地址
// 下面是helloworld的源码package cn.itcast.jvm.t5;// 二进制字节码(类基本信息,常量池,类方法定义 , 包含了虚拟机指令)public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 【lwip】08-ARP协议一图笔记及源码实现
- 小米笔记本Pro15增强版评测_小米笔记本Pro15增强版评测表现
- 用一台笔记本电脑如何赚钱(笔记本电脑赚钱的办法)
- 四 【单片机入门】应用层软件开发的单片机学习之路-----ESP32开发板PWM控制电机以及中断的使用
- 笔记本电脑CF中烟雾头怎么调(win10cf新版本烟雾保护头怎么调)
- 笔记本电脑配置高低怎么区分(笔记本电脑看什么配置判断好坏)
- pytorch、paddlepaddle等环境搭建 深度学习环境搭建常用网址、conda/pip命令行整理
- 三十九 Java开发学习----SpringBoot整合mybatis
- Nacos基本学习
- 数据科学学习手札146 geopandas中拓扑非法问题的发现、诊断与修复