2.1 定义
Heap 堆
通过new关键字,创建对象都会使用堆内存
特点
他是线程共享的,堆中的对象都是需要考虑线程安全的问题
有垃圾回收机制(创建的对象不使用,就会被回收)
2.2 堆内存溢出
由于堆内存有垃圾回收机制,创建出来没有被使用的对象会被回收。但是有没有这种情况:不断创建对象,并且对象还被使用。
还真有,看下面的这个类:
不难看出,我们用创建出来了list 对象,a字符串对象,并且对于list来说,他一直在执行add方法(即对象list一直在被使用),因此list 对象不会被堆内存垃圾回收。同理a字符串对象也一直在执行a+a(即对象a也一直在被使用),因此a对象也不会被堆内存回收。
那么对于此程序,随着while循环的进行,每执行一条"a=a+a"语句,就多一个String类型的对象。结果是对象越来越多,而堆内存是一定的,因此一定会堆内存溢出!
执行程序看验证结果:
其实我们可以修改堆内存的大小,点击idea右上角,打开configurantion:
点击添加虚拟机选项:
进去后在 VM option一栏填写堆内存的大小:
填完堆内存大小后,后点击apply:
再次运行如下程序:
控制台结果(这次i是18就堆内存溢出了!):
2.3 堆内存诊断
2.3.1第一种方式
我们可以在程序运行时关注堆内存的占用情况,jdk8之后要用到以下三个工具:
1.jps 工具:查看当前系统中有哪些java 进程
2.jmap 工具:查看堆内存占用情况,jhdb jmap --heap --pid 进程id
3.jconsole 工具:图形界面的,多功能的检测工具,可以连续检测
下面我们创建一个类,在 main 方法用 sleep方法将程序分割,使得我们有时间去检测sleep方法之前语句执行的堆内存占用情况。类内容如下:
运行程序之后,在控制台终端输入jsp命令,查看现有的java进程及对应的进程号:
在控制台打印了 1…之后2…之前,2…之后3…之前,3…之后,分别用jhsdb jmap --heap --pid 进程号 命令分别查看三个阶段的堆内存占用情况。
打印了 1…之后2…之前:
2…之后3…之前:
3…之后:
2.3.2 第二种方式:jconsole
还是这个程序
运行,在控制台输入:jconsole,选择Demo1_4进程
选择不安全连接:
可以发现堆内存占用随时间的变化: