JVM内功心法-JVM内存模型之内存溢出

JVM内功心法-JVM内存模型之内存溢出

在这里插入图片描述

jvm常用参数【想在本地更快复现一些问题就可以调节这些参数】:

(1-Xms20M 表示设置JVM启动内存的最小值为20M,必须以M为单位

(2-Xmx20M 表示设置JVM启动内存的最大值为20M,必须以M为单位。将-Xmx-Xms设置为一样可以避免JVM内存自动扩展。大的项目-Xmx-Xms一般都要设置到10G、20G甚至还要高

(3-verbose:gc 表示输出虚拟机中GC的详细情况

(4-Xss128k 表示可以设置虚拟机栈的大小为128k

(5-Xoss128k 表示设置本地方法栈的大小为128k。不过HotSpot并不区分虚拟机栈和本地方法栈,因此对于HotSpot来说这个参数是无效的

(6-XX:PermSize=10M 表示JVM初始分配的永久代的容量,必须以M为单位

(7-XX:MaxPermSize=10M 表示JVM允许分配的永久代的最大容量,必须以M为单位,大部分情况下这个参数默认为64M

(8-XX:+HeapDumpOnOutOfMemoryError 表示可以让虚拟机在出现内存溢出异常时Dump出当前的堆内存转储快照

(9-XX:+UseG1GC 表示让JVM使用G1垃圾收集器

(10-XX:+PrintGCDetails 表示在控制台上打印出GC具体细节

(11-XX:+PrintGC 表示在控制台上打印出GC信息

(12-XX:HeapDumpPath=/home/liuke/jvmlogs/2 生成堆文件地址

1. 堆溢出
在计算机科学中, 动态内存分配(Dynamic memory allocation)又称为堆内存分配,是指计算机程序在运行期中分配使用内存。它可以当成是一种分配有限内存资源所有权的方法。 动态分配的内存在被程序员明确释放或被垃圾回收之前一直有效。与静态内存分配的区别在于没有一个固定的生存期。这样被分配的对象称之为有一个“动态生存期”。 《维基百科》
在这里插入图片描述
java.lang.OutOfMemoryError: Java heap space OOM典型的堆内存溢出
思考1:遇到代码不能一眼看出来是哪里出现泄露如何排查?
答:可以借助jproiler工具来分析具体是那一行代码存在大对象导致内存溢出了

堆溢出示例代码:
/**
 * Animal
 *
 * @author OMZ
 * @create 2022/05/03
 */
public class OomTest {

    byte[] bytes = new byte[1 * 1024 * 1024 * 1024];//1G的字节数组 

    public static void main(String[] args) {
        while (true) {
            list.add(new OomTest()); //循环new OomTest的时候字节数组会加载存入堆中
        }
    }

1)生成本次代码运行的dump文件
JVM生成dump文件一般有两种方式
一、 出现OOM时自动生成dump文件
JVM启动命令增加两个参数:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/dump
二、获取PID直接生成当前JVM的dump文件
例如:
jmap -dump:format=b,file=/opt/dump/dump.hprof 1234
其中1234是JVM的当前进程号【jps查询或者ps -ef|grep 项目名查询】
三,idea配置jvm参数生成dump文件
在这里插入图片描述
将生成的文件到导入jprofiler
在这里插入图片描述
可以看到是代码中List占了堆内存,使堆内存溢出了

2. 栈溢出
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

思考1:什么情况下容易栈溢出?

/**
 * Animal
 *
 * @author OMZ
 * @create 2022/05/03
 */
public class StackDemo {

    public static void main(String[] args) {
        new StackDemo().method();
    }

    public void method() {
        method();
    }

}

在这里插入图片描述通常的原因都是无限的递归调用导致的,也就是无限的调用函数,导致空间用完。
3. 方法区溢出
方法区用于存放Class的相关信息,如:类名,访问修饰符,常量池,字符描述,方法描述等。对于这个区域的测试,基本思路是运行时产生大量的类去填满方法区,直到溢出。虽然直接使用Java SE API也可以动态产生类(如反射时的GeneratedConstructorAccessor和动态代理等),但在本次试验使用CGLIB直接操作字节码运行时,生成大量的动态类,当前主流的很多框架 如:Spring,Hibernate对类进行增强时,都会使用到类似CGLIB这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存。
要让方法区溢出就要产生大量类且不能实例化,如果实例化的话会引起堆溢出

4. 永久代溢出(JDK1.7)
5. 元空间溢出(JDK1.8)
其内存空间直接使用的是本地内存,要想让它溢出,那么这台服务器的磁盘一定是接近于爆掉下的情况,一般生产的机器磁盘这些都会有监控,根本达不到溢出的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值