• jvm 三 之堆与栈


    一、堆

    1.1、什么是堆

    Java 堆是虚拟机所管理的内存中最⼤的⼀块,Java 堆是所有线程共享的⼀块内存区域,在虚拟机启动时创建。此内存区域的唯⼀⽬的就是存放对象实例,⼏乎所有的对象实例以及数组都在这⾥分配内存

    1.2、堆中存放的数据

    1.通过new关键 ,创建的对象存放在堆中;
    2.所有线程会共享到同一个堆内存;
    3.在堆内存中是有垃圾回收机制的;

    1.3、内存泄漏出现情况

    堆内存泄漏问题
    内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

    内存泄漏: 创建了很多对象存放在堆内存中,GC回收了很多次就是无法清理该垃圾对象。

    内存泄漏示例1

    • 设置 jvm 测试-Xmx8m 当我们循环把数据 new 出来放到list 中, UserEntity 对象一直被list 引用,无法存放gc 回收,从而内存泄漏 导致 内存溢出
    /**
     * 演示堆内存溢出 -Xmx8m
     *
     * @param args
     */
    public static void main(String[] args) {
        List list = new ArrayList<>();
        while (true) {
            list.add(new UserEntity());
        }
    }
    
    
    public class UserEntity {
        // 申请 1mb 空间
        private byte[] mayiktByte = new byte[1024 * 1024];
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    内存泄漏示例2

    如下示例:
    bytes 如果不设置为null , 就会一直占用空间,就算主动 System.gc(),也无法清理

      public static void main(String[] args) throws InterruptedException {
            System.out.println("1");    // 堆内存 假设 5mb
            Thread.sleep(1000 * 30);    //  阻塞30s
            byte[] bytes = new byte[1024 * 1024 * 10];// 申请10mb内存
            System.out.println("2");    // 堆内存 假设 15mb
            Thread.sleep(1000 * 30);    // 阻塞30s
            bytes = null;               // null GCRoot 引用链
            System.gc();                // 主动调用GC方法  不会立即清理 堆内存垃圾 通知作用
            System.out.println("3");    // gc回收 15-10mb 5mb左右
            Thread.sleep(1000 * 10000);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其他:

    • 1、错误使用了 Threadlocal
    • 2、HashMap 自定义key 可以导致

    1.4、内存溢出:

    内存溢出 一般都是 内存泄漏从而导致的问题, gc回收垃圾对象就是无法回收,在从新向堆内存申请,新的内存存放对象没有空间可以使用

    出现情况:

    • 1、数据库表中 存放几千万条数据---- limit 0,100000 (分页查询 limit 0,20)
    • 2、循环代码 一直new 新的对象存放在我们的集合中, 使用完后未清空,使得JVM不能回收(所有完置空集合,或避免大量数据)
    • 3、使用的第三方软件中的BUG
    • 4、启动参数内存值设定的过小,如最大堆内存10mb (提高堆内存空间)
    • 5、代码中存在死循环或循环产生过多重复的对象实体;

    内存溢出(Out Of Memory)应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的内存。

    1.5、查看堆占用是否过大

    Win操作系统打开任务管理系统 查看到那个进程占用cpu比较高即可

    Linux 可使用arthas(阿尔萨斯) 排查cpu飙高的问题

    # 1.下载阿尔萨斯
    curl -O https://arthas.aliyun.com/arthas-boot.jar 
    2. java -jar arthas-boot.jar
    3. 选择运行的基础进程 输入1
    4. thread -n 3
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.5、排查堆占用对象大小方法

    1、命令

    1.Jps 查看当前系统中有哪些Java进程

    需安装 jdk

    jps                     # 查看当前系统中有哪些Java进程
    jmap -heap 进程id       # 查看堆内存占用情况 
    
    • 1
    • 2

    2、使用图形化界面 Jvisualvm 或者是 jconsole.exe

    jdk 安装目录下
    在这里插入图片描述

    使用 Jvisualvm
    在这里插入图片描述
    查看最大占用的内存
    在这里插入图片描述

  • 相关阅读:
    解决STM32F429烧录程序后还需复位才能植入程序的bug
    使用 WebView2 封装一个生成 PDF 的 WPF 控件
    Go语言笔记
    vue中axios的封装
    教育统计数据生成Word报告?借Aspose.words 小成本实现
    微信小程序---支付
    ThreadLocal:线程中的全局变量
    【JavaWeb】一文搞懂Response
    基于mqtt的物联网控制移动应用程序开发
    python算法例14 整数加法
  • 原文地址:https://blog.csdn.net/qq_41463655/article/details/126147612