1:JVM可视化工具:(JavaVisualVm)
注意:了解安装完该工具后 先看后面的 方法区(元空间)(共享) 与 堆 (共享)
jvisualvm(JDK自带调试工具 JavaVisualVm)
会实时监测JVM中启动的线程 (可以启动一个死循环的线程进行测试)
Visual GC(可视化垃圾回收插件)是需要安装的
可以在JavaVisualVm的 工具栏->工具->插件—>可用插件 安装Visual GC
可能会更新失败,可以采用网上教程解决,或者使用离线安装;
如果需要离线安装:
资源跳转链接:
https://visualvm.github.io/pluginscenters.html
1:把下载下来的 Visual GC插件 通过添加插件的方式添加
2:然后进行安装
3:然后就可以通过 Visual GC 对某个线程进行 可视化垃圾回收监控
离线安装教程:https://blog.csdn.net/qq_39175358/article/details/104708519
2:方法区(元空间)(共享) 详解运行时数据区(内存模型):
使用 javap -v Math.class 查看(反编译 加附带信息)
常量池
1:常量
2:静态变量 (加了static 关键字的 User)
3:类信息 (C++ 类的方法名称等等)
方法区里面的user放的是 user在堆里面的地址
类比于 main线程 main方法栈帧的局部变量表的math 存放的是math这个对象在堆里面的地址
注意:
方法区(元空间) 使用的是直接内存(也就是物理机内存)
方法区(元空间)以前叫做永生代
方法区(元空间) 也会引发full gc 后续会提及
3:堆 (共享) 详解运行时数据区(内存模型):
存放:
如 new出来的Math的 math对象 (非地址 是他的内容)
如 静态变量 (加了static 关键字的 User)的 user对象(非地址 是他的内容)
注意:类加载器 ClassLoader 的对象也是放在堆里面 实际上就是一个对象
堆实际上是什么东西:
默认 老年代:占 三方之二
默认 年轻代:占 三分之一 其中 Eden占 80% s0占10% s1占10%
gc过程(先了解):GCRoot (引用对象 非垃圾对象)
什么是GCRoot 如:方法区中的 静态变量 的 user 如:栈(线程)的 局部变量表中的 math 。。。
先粗略了解:
1:Web应用 new 出来的对象 绝大部分都是先扔年轻代的 Eden
2:如果年轻代的Eden满了 触发步骤3
3:字节码执行引擎 开启一个垃圾回收线程 进行minor gc (回收Eden 和 s0 s1)
1:把GCRoot的非垃圾对象 user math
复制到Survivor区s0 对象的头:年龄+1
2:把Eden 的全部对象全部回收 (包括user math )
4:如果年轻代的Eden又满了 触发步骤5
5:字节码执行引擎 开启一个垃圾回收线程 进行minor gc (回收Eden 和 s0 )
1:把GCRoot的非垃圾对象 复制到 Survivor区s1
2:如果Survivor区s0的对象 user math 不被回收 复制到 Survivor区s1 同时 user math 对象的头:年龄+1
3:把Eden 的全部对象全部回收 (包括user math )
把Survivor区s0 的全部对象回收 (包括user math )
6:如果年轻代的Eden又满了 触发步骤7
7:字节码执行引擎 开启一个垃圾回收线程 进行minor gc (回收Eden 和 s1)
1:把GCRoot的非垃圾对象 复制到 Survivor区s0
2:如果Survivor区s1对象 user math 不被回收 复制到 Survivor区s0 同时 user math 对象的头:年龄+1
3:把Eden 的全部对象全部回收 (包括user math )
把Survivor区s1的全部对象回收 (包括user math )
8:当年龄变成15 (默认)时 会被扔到老年代 (里面静态变量比较多)
4:GC 可视化简单实战
public class HeapTest {
public static void main(String[] args) throws InterruptedException {
ArrayList<Heap> heapArrayList = new ArrayList<>();
while (true){
//不断的new 一个对象
heapArrayList.add(new Heap());
Thread.sleep(100);
}
}
}
public class Heap {
//一个对象里面起码占 100kb内存
byte [] bytes = new byte[1024*100];
}
1:注意时间 Compile Time 和 Class Loader Time
2:注意 GC Time (垃圾回收的时间)
3:注意Eden Space 与 Survivor 0 Survivor 1 的关系
4:注意 Old Gen 缓慢而持续的上升 (当Old Gen满的时候内存溢出 查看代码报错)
5:注意 MetaSpace 方法区保持不动
图1
一开始的 GC 回收次数 为0
Eden在上升
s0 与 s1 为空
Enen满后 进入图2
图2:
此时的 GC 回收次数 为1
s1 获取 Eden 复制过来的 非垃圾回收对象
Eden清空后重新上升
图3:
此时的 GC 回收次数 为2
s0 获取 Eden 复制过来的对象
s0 获取 s1存在的 非垃圾回收对象
s1 清空
Eden清空后重新上升
图2 图3 操作不断重复
当: 在Eden到S0或S1 S0->S1 或者 S1->S0 时计转移次数加1 到达计数15时进 Old Gen
导致Old Gen 缓慢而持续的上升
图四:
当Old Gen 第一次需要进行回收的空间满了: 会触发 full gc 回收整个堆 以及 方法区(元空间) 的垃圾回收对象
但最后full gc都无法回收的时候
如果Old Gen 满了之后会出现异常:OOM 内存溢出
gc 不管 minor gc(时间短)full gc(时间长) 都会出现 stop the world(STW);
stop the world(STW):停止掉用户发起的所有线程 (比如下单),避免在收集垃圾的过程中产生新的垃圾
java虚拟机调优就是减少 stop the world(STW)的过程
5:JVM内存分配设置
Spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里):
java
‐Xms2048M ‐Xmx2048M ‐Xmn1024M
‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
‐Xss512K
‐jar microservice‐eureka‐server.jar
方法区(元空间):
推荐设置 JVM 的元空间大小(不然可能导致大一点的程序启动特别慢):
关于元空间的JVM参数有两个:-XX:MetaspaceSize=N和 -XX:MaxMetaspaceSize=N
-XX:MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
-XX:MetaspaceSize:
指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认是21M,
达到该值就会触发full gc进行类型卸载, 容量分配大小的扩展机制 会对该值进行调整:
容量分配大小的扩展机制:
如果释放了大量的空间, 就适当降低该值;
如果释放了很少的空间, 那么在不超过-XX:MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。
这个跟早期jdk版本的-XX:PermSize参数意思不一样,-XX:PermSize代表永久代的初始容量。
方法区(元空间): 以前叫永久代使用物理机内存
栈(线程):
‐Xss512K 是指每给线程 512k
-Xss设置越小count值越小,说明一个线程栈里能分配的栈帧就越少,但是对JVM整体来说能开启的线程数会更多
在不调节 -Xss的时候 默认是1m 可以调用23538次 redo方法 产生23538个redo栈帧
在调节 -Xss为128k的时候 可调用1088次 redo方法 产生1088个redo栈帧
线程结束:栈(线程)内存马上释放
特别注意:我们是没有办法设置系统能开多少个线程的
public class ThreadStackOverflowTest {
//JVM设置
// - Xss 128k -Xss 默认 1M
static int count = 0;
/**
* 每一次 调用redo的时候
* main线程 都新增一个 redo 的栈帧
*/
static void redo(){
count ++;
redo();
}
public static void main(String[] args) {
try{
redo();
}catch (Throwable e){
e.printStackTrace();
System.out.println(count);
}
}
}
项目连接
请配合项目代码食用效果更佳:
项目地址:
https://github.com/hesuijin/hesuijin-study-project
Git下载地址:
https://github.com.cnpmjs.org/hesuijin/hesuijin-study-project.git
jvm-module项目模块下 jvmMemoryModel包
网友评论