JVM专题-堆(heap)

Posted IT老刘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM专题-堆(heap)相关的知识,希望对你有一定的参考价值。

1.定义


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 指令查看内存情况

程序运行后

8776为该进程的pid,调用命令


具体的堆内存占用在Heap Usage

在程序打印了 2… 后,再次

在打印了 3… 之后,代表着已经被垃圾回收了

3.2.jconsole诊断堆内存



但是在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];
}


经过测试,在执行了垃圾回收后,堆内存占用还是居高不下。
于是点击 堆dump 拿取快照,分析详情

点击查看

由源代码可知,确实是Student类的原因。
student数组一直在循环引用,没有被垃圾回收。

以上是关于JVM专题-堆(heap)的主要内容,如果未能解决你的问题,请参考以下文章

JVM技术专题让你完全攻克内存溢出(OOM)这一难题「案例篇」

Java技术专题-JVM研究系列(26)让你完全攻克内存溢出(OOM)这一难题

Java堆内存Heap与非堆内存Non-Heap

JVM知识

JVM 内存初学 (堆(heap)栈(stack)和方法区(method) )

JVM 内存初学 (堆(heap)栈(stack)和方法区(method) )