在上篇的时候我们介绍了JVM各部分的职责与概念,在这篇文章中,我要继续介绍堆内存的概念与垃圾回收部分。
1.堆(Heap)
一个JVM中只有一个堆,堆内存的大小是可以调节的。
类加载器读取了class文件后,会将 类的实例对象,方法,常量,变量,以及所有引用类型的真实对象保存在堆中。
我们还可以对堆内存进行细分为下图:
对新生区区垃圾回收为轻GC,对老年区垃圾回收为重GC(Full GC),一般当养老区都要满了的时候才会进行重GC。
永久区
这个区域常驻于内存中,用来存放JDK自身携带的Class对象,接口元数据。存储的是Java运行的一些环境。不存在垃圾回收,关闭虚拟机的时候释放永久区的内存。
jdk1.6以前:永久区,常量池在方法区。
jdk1.7:永久区,常量池在堆中。
jdk1.8之后:无永久区,改为元空间,方法区在元空间中。
2.JVM调优
堆内存满了会报OutOfMemoryError内存溢出错误,遇到这种问题我们应该先调整JVM的内存大小。
// 返回虚拟机试图使用的最大内存,单位为字节
Runtime.getRuntime().maxMemory();
// 返回JVM的初始化总内存,单位为字节
Runtime.getRuntime().totalMemory();
我们启动的时候可以通过设置JVM参数进行调整
// 设置JVM初始化分配的内存,默认为本机内存的1/64
-Xms1024m
// 设置JVM允许分配的最大内存,默认为本机内存的1/4
-Xmx1024m
// 输出GC的信息到控制台
-XX:PrintGCDetails
// 如果报了OutOfMemoryError错误就Dump文件
// On后面为当哪种错误或异常出现时Dump文件,相当于条件
-XX:HeapDumpOnOutOfMemoryError
3.JProfiler
当我们遇到了OOM(内存溢出异常),我们可能需要用到内存快照分析工具。JProfiler就是用来做这个的工具。
我们可以去IDEA中的File —> Settings —> Plugins —> 搜索JProfier进行下载。
同时我们需要下载一个客户端,我们搜索JProfiler就可以。
JProfiler客户端下载地址 注:安装的路径中不可有中文或空格
我们还需要将下载的客户端bin文件夹中的exe文件在IDEA中与JProfiler文件关联上才能够使用。
作用:
1.分析Dump内存文件,快速定位内存泄漏。
2.获得堆中的数据。
3.获得大的对象。
4.GC介绍
JVM在进行GC的时候,大部分都是回收新生区
复制算法:
每次GC的时候将Eden区与幸存区from内的对象放入幸存区to,此时幸存区from应该为空的,改为幸存区to。
好处:没有内存的碎片
坏处:要牺牲一个幸存区的空间作为幸存区to
标记压缩清除算法:
标记:当我们在堆内存储对象的时候,通过扫描去标记活着的对象。
清除:对没有标记的对象进行清除。
这样就不会浪费一块幸存区空间。
但是这样会产生其他问题,就是清除垃圾后会产生内存碎片;并且扫描去标记,扫描去清除会浪费时间。
标记压缩就是在标记清除算法基础上进行了优化。
压缩:再次扫描,将存活的对象向一段移动,去除内存碎片。
JVM就先介绍到这里,希望对你有所帮助。