通过new关键字,创建的对象都会使用堆内存。 特点:
- 它是线程共享的,堆中的对象都需要考虑到线程安全的问题
- 有垃圾回收的机制,堆中不再被引用的对象,会被垃圾回收释放掉对应的内存。
堆内存溢出
虽然有垃圾回收机制来对堆中的垃圾进行“清理”,但是当我们不断往堆内存中放入新对象,同时旧对象因为仍在使用而不能被释放,这个时候就会出现堆溢出。
package cn.itcast.jvm.t1.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);
}
}
}
上述代码就是不断往堆中创建新的对象,导致堆溢了 爆出OutOfMemoryError 堆溢出错误 Java heap space 并指出是堆空间。 在我们执行java程序时,可以通过java虚拟机参数来指定java堆的大小 -Xmx size 指定堆最大大小为size -Xms size 指定堆最小大小为size 当我们的堆内存设置的比较大时,不容易暴露内存溢出问题,所以如果想更快的暴露是否存在堆内存溢出问题,所以可以给堆内存设置一个更小的大小。
堆内存诊断
- jps工具 用于查看当前系统有哪些java进程。 显示出进程id 【jps】
- jmap工具 用于查看某一个时刻堆内存占用情况。 【jmap -heap 进程id】
- jconsole工具 提供一个图形界面,实现多功能的检测工具,并且可以实现连续检测。【jconsole】
package cn.itcast.jvm.t1.heap;
/**
* 演示堆内存
*/
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);
}
}
上述代码中可以提供三个阶段
- 第一个阶段,还没有分配byte数组,这个时候伊甸园区只有程序启动时的内存占用,其他区域已使用内存都是0
- 第二个阶段,我们new了一个10m大小的byte数组,那么在伊甸园区就会新分配大约10M的内存空间出来
- 第三个阶段,我们将byte数组的引用对象设置为null,并调用垃圾回收,系统将进行一次垃圾回收操作。
可以看到伊甸园中的内存,大部分都被回收掉了。
jconsole的使用,可以看到图形界面中堆内存经历了一次堆内存分配,随后堆内存因为垃圾回收而陡然下降
案例 垃圾回收后,垃圾占用依然很高 我们使用一个更加智能的工具Jvisualvm工具 其中提供一个内存转储功能,即右上角的“堆 Dump”可以分析出堆内存占用更加详细的功能,这是之前jmap、jconsole工具所不具备的。 进一步查找堆内存中占用大小排名前N的对象的详细信息。 可以看到最占堆内存的是一个ArrayList对象,可以看到原来这个数组中放了200个Student对象,并且每个Student对象占用比较大的内存。
从我们的源代码中可以证实这一点
package cn.itcast.jvm.t1.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];
}
1 条评论
回复