2.内存结构(堆)

zhanglei 2022年06月13日 260次浏览

image-20220613153744795

2.1 定义

​ Heap 堆

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

​ 特点

​ 他是线程共享的,堆中的对象都是需要考虑线程安全的问题

​ 有垃圾回收机制(创建的对象不使用,就会被回收)

2.2 堆内存溢出

​ 由于堆内存有垃圾回收机制,创建出来没有被使用的对象会被回收。但是有没有这种情况:不断创建对象,并且对象还被使用。

​ 还真有,看下面的这个类:

image-20220613155533183

​ 不难看出,我们用创建出来了list 对象,a字符串对象,并且对于list来说,他一直在执行add方法(即对象list一直在被使用),因此list 对象不会被堆内存垃圾回收。同理a字符串对象也一直在执行a+a(即对象a也一直在被使用),因此a对象也不会被堆内存回收。

​ 那么对于此程序,随着while循环的进行,每执行一条"a=a+a"语句,就多一个String类型的对象。结果是对象越来越多,而堆内存是一定的,因此一定会堆内存溢出!

​ 执行程序看验证结果:

image-20220613175841059

​ 其实我们可以修改堆内存的大小,点击idea右上角,打开configurantion:

image-20220613180103531

​ 点击添加虚拟机选项:

image-20220613180233346

​ 进去后在 VM option一栏填写堆内存的大小:

image-20220613180504032

​ 填完堆内存大小后,后点击apply:

image-20220613180711797

​ 再次运行如下程序:

image-20220613155533183

​ 控制台结果(这次i是18就堆内存溢出了!):

image-20220613180908675

2.3 堆内存诊断

2.3.1第一种方式

我们可以在程序运行时关注堆内存的占用情况,jdk8之后要用到以下三个工具:

​ 1.jps 工具:查看当前系统中有哪些java 进程

​ 2.jmap 工具:查看堆内存占用情况,jhdb jmap --heap --pid 进程id

​ 3.jconsole 工具:图形界面的,多功能的检测工具,可以连续检测

下面我们创建一个类,在 main 方法用 sleep方法将程序分割,使得我们有时间去检测sleep方法之前语句执行的堆内存占用情况。类内容如下:

image-20220613194651223

​ 运行程序之后,在控制台终端输入jsp命令,查看现有的java进程及对应的进程号:

image-20220613203621114

在控制台打印了 1…之后2…之前,2…之后3…之前,3…之后,分别用jhsdb jmap --heap --pid 进程号 命令分别查看三个阶段的堆内存占用情况。

打印了 1…之后2…之前:

image-20220613204437571

2…之后3…之前:

image-20220613204643831

3…之后:

image-20220613204814041

2.3.2 第二种方式:jconsole

​ 还是这个程序

image-20220613205301858

​ 运行,在控制台输入:jconsole,选择Demo1_4进程

image-20220613205356407

​ 选择不安全连接:

image-20220613205412308

​ 可以发现堆内存占用随时间的变化:

image-20220613210031228