文章目录


1.定义

JVM专题(四)-堆(heap)_内存溢出
Heap堆

  • 通过new关键字,创建对象都会使用堆内存

特点

  • 它是线程共享的,堆中对象都需要考虑线程安全的问题
  • 有垃圾回收机制

2.堆内存溢出

OutOfMemoryError:java heap space 堆内存溢出

堆空间调整参数

-Xmx空间大小
-Xmx4G

案例

package com.heap;

import java.util.ArrayList;
import java.util.List;

/**
* 演示堆内存溢出 java.lang.OutOfMemoryError: Java heap space
* -Xmx8m
*/
public class Demo1_5 {

public static void main(String[] args) {
int i = 0;
try {
List<String> list = new ArrayList<>();
String a = "hello";
while (true) {
list.add(a); // hello, hellohello, hellohellohellohello ...
a = a + a; // hellohellohellohello
i++;
}
} catch (Throwable e) {
e.printStackTrace();
System.out.println(i);
}
}
}

结果:

java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:421)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at com.heap.Demo1_5.main(Demo1_5.java:19)
26

在实际生产中,对于堆内存溢出问题,可能宾士那么容易检测出来。因为堆内存空间比较大,在运行时,一时间还不会使其溢出。

所以为了使堆内存问题尽早暴露出来,可以在测试时,将堆内存空间调整小一些。

3.堆内存诊断

  • jps工具
    查看当前系统中有哪些java进程
  • jmap工具
    查看某一时刻堆内存占用情况

jmap -heap 进程id

  • jconsole工具
    图形界面的,多功能的监测工具,可以连续监测
    堆内存调整指令参数
    -Xmx容量

3.1.jmp诊断堆内存

案例代码

/**
* 演示堆内存
*/
public class Demo1_4 {

public static void main(String[] args) throws InterruptedException {
System.out.println("1...");
Thread.sleep(30000);
byte[] array = new byte[1024 * 1024 * 10]; // 10 Mb
System.out.println("2...");
Thread.sleep(20000);
array = null;
System.gc();
System.out.println("3...");
Thread.sleep(1000000L);
}
}

Thread.sleep 是为了留有时间间隔执行命令,监控进程状态
程序打印 1… 后,执行jps查看该进程的进程号
​​​jmap -heap 进程id​​​,查看这一时刻进程堆空间使用情况
程序打印 2… 后,再次执行 jmap 指令查看内存情况
程序打印 3… 后,再次执行 jmap 指令查看内存情况

程序运行后
JVM专题(四)-堆(heap)_后端_02
8776为该进程的pid,调用命令
JVM专题(四)-堆(heap)_开发语言_03
JVM专题(四)-堆(heap)_后端_04
具体的堆内存占用在Heap Usage
JVM专题(四)-堆(heap)_堆内存_05

在程序打印了 2… 后,再次
JVM专题(四)-堆(heap)_后端_06
在打印了 3… 之后,代表着已经被垃圾回收了
JVM专题(四)-堆(heap)_开发语言_07

3.2.jconsole诊断堆内存

JVM专题(四)-堆(heap)_开发语言_08
JVM专题(四)-堆(heap)_后端_09
但是在jconsole里面可以看出,在给array初始化后,堆内存使用量增加了10M,在垃圾回收后,堆内存使用量又迅速下降。

3.3.jvisualvm诊断堆内存

jvisualvm是功能更加强大的图形化jvm管理软件。可以进行堆转储,拿到进程某一时刻的快照dump进行分析。

案例代码:

package com.heap;

import java.util.ArrayList;
import java.util.List;

/**
* 演示查看对象个数 堆转储 dump
*/
public class Demo1_13 {

public static void main(String[] args) throws InterruptedException {
List<Student> students = new ArrayList<>();
for (int i = 0; i < 200; i++) {
students.add(new Student());
// Student student = new Student();
}
Thread.sleep(1000000000L);
}
}
class Student {
private byte[] big = new byte[1024*1024];
}

JVM专题(四)-堆(heap)_内存溢出_10
经过测试,在执行了垃圾回收后,堆内存占用还是居高不下。
于是点击 堆dump 拿取快照,分析详情
JVM专题(四)-堆(heap)_后端_11
点击查看
JVM专题(四)-堆(heap)_堆内存_12
由源代码可知,确实是Student类的原因。
student数组一直在循环引用,没有被垃圾回收。