实战 内存溢出定位与分析

环境搭建

/** * 模拟测试插入一百万条字符串[image.png](https://img.hacpai.com/file/2019/08/image-dd10de62.png)                str += UUID.randomUUID().toString();            }            list.add(str);        }        System.out.println("ok");    }}

结果:

java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid10272.hprof ...Heap dump file created [8323049 bytes in 0.028 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:3332)at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)at java.lang.StringBuilder.append(StringBuilder.java:136)at cn.jeff.test.Test01.main(Test01.java:18)Process finished with exit code 1

参数中设置了输出dump文件,默认输出在项目根目录下。

问题分析(基于MAT):

可以看出87.93%的内存被Object[]数组占用了,通常情况下不会出现这么高的占用
再去看详细的数据情况:


可以看出在Object[]数组中装满了刚才生产的UUID,导致了最后的系统内存溢出问题。

分析线程执行情况:jstack

线程知识回顾


线程的六种状态

  1. 初始态(NEW)
    创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态。

  2. 运行态(RUNNABLE),在Java中,运行态包括 就绪态 和 运行态。
    2.1 就绪态 :
    该状态下的线程已经获得执行所需的所有资源,只要CPU分配执行权就能运
    行。
    所有就绪态的线程存放在就绪队列中。
    2.2 运行态 :
    获得CPU执行权,正在执行的线程。
    由于一个CPU同一时刻只能执行一条线程,因此每个CPU每个时刻只有一条
    运行态的线程。

  3. 阻塞态(BLOCKED)
    当一条正在执行的线程请求某一资源失败时,就会进入阻塞态。
    而在Java中,阻塞态专指请求锁失败时进入的状态。
    由一个阻塞队列存放所有阻塞态的线程。
    处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执
    行。

  4. 等待态(WAITING)
    当前线程中调用wait、join、park函数时,当前线程就会进入等待态。
    也有一个等待队列存放所有等待态的线程。
    线程处于等待态表示它需要等待其他线程的指示才能继续运行。进入等待态的线程会释放CPU执行权,并释放资源(如:锁)

  5. 超时等待态(TIMED_WAITING)
    当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就
    会进入该状态;
    它和等待态一样,并不是因为请求不到资源,而是主动进入,并且进入后需要其
    他线程唤醒;
    进入该状态后释放CPU执行权 和 占有的资源。
    与等待态的区别:到了超时时间后自动进入阻塞队列,开始竞争锁。

  6. 终止态(TERMINATED)
    线程执行结束后的状态。

实战:死锁问题

构建死锁环境

public class TestDeadLock {    //    定义两个锁    private static Object obj1 = new Object();    private static Object obj2 = new Object();    public static void main(String[] args) {//        创建初始态线程        Thread thread1 = new Thread(new Thread1());        Thread thread2 = new Thread(new Thread2());//        就绪态        thread1.start();        thread2.start();    }    //    第一个线程    private static class Thread1 implements Runnable {        @Override        public void run() {            synchronized (obj1) {//                此时得到了obj1这个锁                System.out.println("Thread1得到了obj1这把锁!");                try {//                停下来休息两秒 为了让Thread2得到obj2这把锁 造成死锁 sleep方法是不会释放锁的                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                synchronized (obj2) {                    System.out.println("Thread1得到了obj2这把锁!");                }            }        }    }    //    第二个线程    private static class Thread2 implements Runnable {        @Override        public void run() {//        得到obj2这把锁            synchronized (obj2) {                System.out.println("Thread2得到了obj2这把锁!");                try {//            为了让obj1被先得到                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }//            得到obj1                synchronized (obj1) {                    System.out.println("Thread2得到了obj1这把锁!");                }            }        }    }}

结果

[root@hadoop101 jvm]# javac TestDeadLock.java[root@hadoop101 jvm]# java TestDeadLockThread1得到了obj1这把锁!Thread2得到了obj2这把锁!# 程序卡在这里

保持程序的运行状态,另外创建一个xshell命令行窗口

# 通过jps找到运行的TestDeadLock程序的端口[root@hadoop101 ~]# jps2956 TestDeadLock3038 Jps1967 Bootstrap# 指令格式:jstack 端口号[root@hadoop101 ~]# jstack 29562019-08-16 02:43:12Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.111-b14 mixed mode):"Attach Listener" #11 daemon prio=9 os_prio=0 tid=0x00007ffa54001000 nid=0xbf4 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x00007ffa7c008800 nid=0xb8d waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"Thread-1" #9 prio=5 os_prio=0 tid=0x00007ffa7c0ca800 nid=0xb97 waiting for monitor entry [0x00007ffa6c51d000]   java.lang.Thread.State: BLOCKED (on object monitor)at TestDeadLock$Thread2.run(TestDeadLock.java:52)- waiting to lock <0x00000000e345be78> (a java.lang.Object)- locked <0x00000000e345be88> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)"Thread-0" #8 prio=5 os_prio=0 tid=0x00007ffa7c0c9000 nid=0xb96 waiting for monitor entry [0x00007ffa6c61e000]   java.lang.Thread.State: BLOCKED (on object monitor)at TestDeadLock$Thread1.run(TestDeadLock.java:31)- waiting to lock <0x00000000e345be88> (a java.lang.Object)- locked <0x00000000e345be78> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007ffa7c0b3000 nid=0xb94 runnable [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007ffa7c0b0000 nid=0xb93 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007ffa7c0ad800 nid=0xb92 waiting on condition [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007ffa7c0ac000 nid=0xb91 runnable [0x0000000000000000]   java.lang.Thread.State: RUNNABLE"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007ffa7c079000 nid=0xb90 in Object.wait() [0x00007ffa6cc24000]   java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x00000000e3408e98> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)- locked <0x00000000e3408e98> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007ffa7c074800 nid=0xb8f in Object.wait() [0x00007ffa6cd25000]   java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x00000000e3406b40> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)- locked <0x00000000e3406b40> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)"VM Thread" os_prio=0 tid=0x00007ffa7c06d000 nid=0xb8e runnable"VM Periodic Task Thread" os_prio=0 tid=0x00007ffa7c0b6000 nid=0xb95 waiting on conditionJNI global references: 6Found one Java-level deadlock:============================="Thread-1":  waiting to lock monitor 0x00007ffa600062c8 (object 0x00000000e345be78, a java.lang.Object),  which is held by "Thread-0""Thread-0":  waiting to lock monitor 0x00007ffa60004e28 (object 0x00000000e345be88, a java.lang.Object),  which is held by "Thread-1"Java stack information for the threads listed above:==================================================="Thread-1":at TestDeadLock$Thread2.run(TestDeadLock.java:52)- waiting to lock <0x00000000e345be78> (a java.lang.Object)- locked <0x00000000e345be88> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)"Thread-0":at TestDeadLock$Thread1.run(TestDeadLock.java:31)- waiting to lock <0x00000000e345be88> (a java.lang.Object)- locked <0x00000000e345be78> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)# 系统提示发现一个死锁Found 1 deadlock.

死锁分析:

"Thread-1" #9 prio=5 os_prio=0 tid=0x00007ffa7c0ca800 nid=0xb97 waiting for monitor entry [0x00007ffa6c51d000]   java.lang.Thread.State: BLOCKED (on object monitor)at TestDeadLock$Thread2.run(TestDeadLock.java:52)- waiting to lock <0x00000000e345be78> (a java.lang.Object)- locked <0x00000000e345be88> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)"Thread-0" #8 prio=5 os_prio=0 tid=0x00007ffa7c0c9000 nid=0xb96 waiting for monitor entry [0x00007ffa6c61e000]   java.lang.Thread.State: BLOCKED (on object monitor)at TestDeadLock$Thread1.run(TestDeadLock.java:31)- waiting to lock <0x00000000e345be88> (a java.lang.Object)- locked <0x00000000e345be78> (a java.lang.Object)at java.lang.Thread.run(Thread.java:745)

可以看出:
Thread-1:正在手握着0x00000000e345be88这个锁,等待着0x00000000e345be78的获取;
Thread-0:正在手握着0x00000000e345be78这个锁,等待着0x00000000e345be88的获取;

VisualVM工具的使用

简介

VisualVM,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。
VisualVM使用简单,几乎0配置,功能还是比较丰富的,几乎囊括了其它JDK自带命令的所有功能。
1、内存信息
2、线程信息
3、Dump堆(本地进程)
4、Dump线程(本地进程)
5、打开堆Dump。堆Dump可以用jmap来生成。
6、打开线程Dump
7、生成应用快照(包含内存信息、线程信息等等)
8、性能分析。
9、CPU分析(各个方法调用时间,检查哪些方法耗时多)
10、内存分析(各类对象占用的内存,检查哪些类占用内存多

使用方法

启动

VisualVM在jdk的安装目录的bin下面有jvisualvm.exe,打开便可使用。

内存溢出_JVM|03内存溢出实战相关推荐

  1. jvm内存模型_JVM|02内存模型

    JVM内存模型 概述 Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保 ...

  2. java 64位 默认分配内存大小_JVM默认内存大小

    堆(Heap)和非堆(Non-heap)内存 按照官方的说法:"Java虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在Java虚拟机启动时创建的." ...

  3. java线程多栈会溢出_JVM 栈(stack)溢出案例

    介绍 当启动一个新线程时,JVM就会给这个线程分配一个Java栈(这个栈的内存大小由-Xss参数来设置). 一个Java栈的基本单位是帧,每一次函数调用就会生成栈帧,占用一定的栈空间.当函数本身需要的 ...

  4. 运行时错误7内存溢出_JVM运行时内存数据区域

    阅读本文大概需要5分钟 作者:AI乔治出处:https://my.oschina.net/u/3611782/blog/4530512 1 讨论背景 周志明老师写的<深入理解Java虚拟机> ...

  5. java 内存溢出 内存泄露_JVM——内存泄漏与内存溢出

    1.内存溢出 1.1 什么是Java的内存溢出? 在Java程序运行的过程中,经常会碰到以下错误:java.lang.OutOfMemoryError. 通俗讲,内存溢出是指程序在申请内存时,没有足够 ...

  6. linux 内存溢出排查_java 内存溢出 栈溢出的原因与排查方法

    1. 内存溢出的原因是什么? 内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出.如果出现这种现象可行代码排查: 一)是否应用中的类中和引用变量过多使用了Static修饰 ...

  7. java内存区域与内存溢出异常_Java内存区域与内存溢出异常

    Java的内存管理是一个老生常谈的问题,虽然Java号称可以自动管理自己的内存,使程序员从内存管理的围墙解放出来,但是一连串的内存泄漏和溢出方面的问题,使得我们不得不去深入了解Java的内存管理机制. ...

  8. 46栈内存溢出、内存区域(程序计数器、Java 虚拟机栈、本地方法栈、Java 堆、方法区、直接内存、内存溢出)与内存溢出(对象实例化分析)

    46.什么情况下会发生栈内存溢出 46.1.Java 内存区域与内存溢出 46.1.1.内存区域 46.1.1.1.程序计数器 46.1.1.2.Java 虚拟机栈 46.1.1.3.本地方法栈 46 ...

  9. android 避内存溢出,Android避免内存溢出(Out of Memory)方法总结

    Android避免内存溢出(Out of Memory)方法总 结 避免内存溢出的方法,主要是对以下三个方面对程序进行优化武汉Android培训 内存引用 在处理内存引用之前,我们先来复习下什么是强引 ...

最新文章

  1. ARTS打卡计划第四周-ALGORITHM
  2. Firefox 44.0将在Linux上启用H.264支持:GTK3仍缺席
  3. 利用BADI ME_PROCESS_PO_CUST進行PO check
  4. 计算机粘贴功能不能用了,电脑复制粘贴不能用了【解决办法】
  5. beanpostprocessor与@autowired的关系
  6. 如何配置SAP Analytics Cloud到SAP Cloud for Customer的连接
  7. java什么是重构 何时使用重构_Java 之重构现有系统实战(一)
  8. Kubernetes架构及相关服务详解
  9. MFC对话框响应ON_UPDATE_COMMAND_UI事件
  10. Android基础 --- Widget
  11. JS call()与apply()的用法
  12. Rust 1.7.0 处理命令行參数
  13. UVALive 3401 彩色立方体
  14. web前端面试题总结
  15. mac设置第三方输入法为默认输入法
  16. 如何向iphone手机网易云音乐添加本地音乐
  17. 动态平衡网格交易_网格交易 套利:期货经典书籍
  18. Masked Siamese Networksfor Label-Efficient Learning
  19. WPF的打印原理 实现打印页眉页脚和打印预览
  20. 深度:戴尔中国十年之变

热门文章

  1. rhel dns 配置
  2. 关于jQuery的$.getJSON乱码问题
  3. positionnbsp;absolutenbsp;relativenbsp;z-index
  4. WinAPI: midiOutReset - 重置输出设备
  5. 2019最全Python入门学习路线,绝对是最全
  6. LOJ#6044. 「雅礼集训 2017 Day8」共(Prufer序列)
  7. Flutter - sqflite(原滋原味)
  8. 华为交换机配置DHCP服务器
  9. 字符串中包含汉字和\u,显示出汉字来
  10. Cordova实战培训