视频学习:【狂神说Java】JVM快速入门篇
相关资料:
- 《深入理解Java虚拟机》第三版
- 面经手册 · 第25篇《JVM内存模型总结,有各版本JDK对比、有元空间OOM监控案例、有Java版虚拟机,综合学习更容易!》
6、JDK1.6~1.8内存模型演变
图源:bugstack虫洞栈:面经#25
- 这些行 每一个都会对应一条需要执行的字节码指令,是压栈还是弹出或是执行计算。
- 之所以说是线程私有的,因为如果不是私有的,那么整个计算过程最终的结果也将错误。
8、栈(Stack)
在计算机流传有一句废话: 程序 = 算法 + 数据结构
但是对于大部分同学都是: 程序 = 框架 + 业务逻辑
栈:后进先出 / 先进后出
队列:先进先出(FIFO : First Input First Output)
谁空谁是to
GC垃圾回收主要是在新生区和养老区,又分为轻GC 和 重GC,如果内存不够,或者存在死循环,就会导致
新生区
新生区是类诞生,成长,消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。
新生区又分为两部分:伊甸区(Eden Space)和幸存者区(Survivor Space),所有的类都是在伊甸区
- 被new出来的,幸存区有两个:0区 和 1区,当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收(Minor GC)。
- 将伊甸园中的剩余对象移动到幸存0区,若幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。
- 那如果1区也满了呢这里幸存0区和1区是一个互相交替的过程)再移动到养老区;
- 若养老区也满了,那么这个时候将产生MajorGC(Full GC),进行养老区的内存清理,
- 若养老区执行了Full GC后发现依然无法进行对象的保存,就会产生OOM异常 。
如果出现 java.lang.OutOfMemoryError:java heap space异常,说明Java虚拟机的堆内存不够,原因如下:
- Java虚拟机的堆内存设置不够,可以通过参数 -Xms(初始值大小),-Xmx(最大大小)来调整。
- 代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)或者死循环
永久区(Perm)
永久存储区是一个常驻内存区域:
- 用于存放JDK自身所携带的Class,Interface的元数据,
- 也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用的内存。
如果出现 ,说明是 Java虚拟机对永久代Perm内存设置不够。
一般出现这种情况,都是程序启动需要加载大量的第三方jar包,例如:在一个Tomcat下部署了太多的应用。或者大量动态反射生成的类不断被加载,最终导致Perm区被占满。
注意:
Jdk1.6之前: 有永久代,常量池1.6在方法区
Jdk1.7: 有永久代,但是已经逐步 “去永久代”,常量池1.7在堆
Jdk1.8及之后:无永久代,常量池1.8在元空间
在JDK8以后,永久存储区改了个名字(元空间)
- JDK 1.8 JVM 的内存结构主要由三大块组成:堆内存、元空间和栈,Java 堆是内存空间占据最大的一块区域。
- Java 堆,由年轻代和年老代组成,分别占据 1/3 和 2/3。
- 而年轻代又分为三部分,Eden、From Survivor、To Survivor,占据比例为 8:1:1,可调。
- 另外这里我们特意画出了元空间,也就是直接内存区域。在 JDK 1.8 之后就不在堆上分配方法区了。
- 元空间从虚拟机 Java 堆中转移到本地内存,默认情况下,元空间的大小仅受本地内存的限制,说白了也就是以后不会因为永久代空间不够而抛出 OOM 异常出现了。
- jdk1.8 以前版本的 class 和 JAR 包数据存储在 PermGen 下面 ,PermGen 大小是固定的,而且项目之间无法共用,公有的 class,所以比较容易出现 OOM 异常。
熟悉三区结构后方可学习JVM垃圾回收机制
实际而言,方法区(Method Area)和堆一样,是各个线程共享的内存区域:
它用于存储虚拟机加载的:类信息+普通常量+静态常量+编译器编译后的代码,
虽然JVM规范将方法区描述为堆的一个逻辑部分,但它却还有一个别名,叫做Non-Heap(非堆),目的就是要和堆分开。
对于HotSpot虚拟机,很多开发者习惯将方法区称之为 “永久代(Parmanent Gen)”,但严格本质上说两者不同,或者说使用永久代实现方法区而已,永久代是方法区(相当于是一个接口interface)的一个实现,Jdk1.7的版本中,已经将原本放在永久代的字符串常量池移走。
常量池(Constant Pool)是方法区的一部分,Class文件除了有类的版本,字段,方法,接口描述信息外,还有一项信息就是常量池,这部分内容将在类加载后进入方法区的运行时常量池中存放!
发现,默认的情况下分配的内存是总内存的 1/4,而初始化的内存为 1/64 !
VM参数调优:把初始内存,和总内存都调为 1024M,运行,查看结果!
再次证明:元空间并不在虚拟机中,而是使用本地内存。
测试2
代码:
vm参数:
测试,查看结果!
user – 总计本次 GC 总线程所占用的总 CPU 时间
sys – OS 调用 or 等待系统时间
real – 应用暂停时间
如果GC 线程是 Serial Garbage Collector 串行搜集器的方式的话(只有一条GC线程,), real time 等于user 和 system 时间之和。
通过日志发现Young的区域到最后 GC 之前后都是0,old 区域 无法释放,最后 堆溢出错误。
其他文章链接
一文读懂 – 元空间和永久代
Java方法区、永久代、元空间、常量池详解
10、Dump内存快照
在运行java程序的时候,有时候想测试运行时占用内存情况,这时候就需要使用测试工具查看了。在
eclipse里面有 Eclipse Memory Analyzer tool(MAT) 插件可以测试,而在idea中也有这么一个插件,
就是JProfifiler,一款性能瓶颈分析工具!
作用:
-
分析Dump文件,快速定位内存泄漏;
-
获得堆中对象的统计数据
-
获得对象相互引用的关系
-
采用树形展现对象间相互引用的情况
2、安装JPro?ler监控软件
下载地址:https://www.ej-technologies.com/download/jpro?ler/version_92
4、注册
自行搜索解决即可(或者到狂神视频截图下载也行哈哈)
5、配置IDEA运行环境
Settings–Tools–JPro?ier–JPro?ier executable选择JPro?le安装可执行文件。(如果系统只装了一个版本, 启动IDEA时会默认选择)保存
寻找文件:

从软件开发的角度上,dump文件就是当程序产生异常时,用来记录当时的程序状态信息(例如堆栈的状态),用于程序开发定位问题。
文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92242 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!