JVM 堆

定义

像程序计数器、本地方法栈、虚拟机栈都是线程私有的,而堆(Heap)、方法区都是线程共享的区域。通过new关键字创建的对象都会使用堆内存。

特点

  • 它是线程共享的,堆中对象都需要考虑线程安全的问题。
  • 有垃圾回收机制,即堆中不再被引用的对象就会当成垃圾进行回收,已释放空闲的内存,这样不至于堆被创建的对象给撑爆。

堆内存溢出

堆内存有垃圾回收器,为何还会存在堆内存溢出问题呢?

比如,对象被当做垃圾回收的条件是这个对象没人再使用他,但是如果不断的产生对象,而产生的这些新对象仍然有人在使用他呢?是不是意味着这些对象不能作为垃圾呢,这样达到一定数量之后,堆内存可能就会被耗尽,所以会堆内存溢出。

代码演示
// 演示堆内存溢出
public class Demo {
	public static void main(String[] args) {
		int i = 0;
		try {
			List<String> list = new ArrayList<>();
			String a = "asd";
			while (true) {
				list.add(a);
				a = a + a;
				i++;
			}
		}catch(Throwable e) {
			e.printStackTrace();
			print(i);
		}
	}
}

有list集合,还有初始值为“asd”的字符串,然后每循环一次把字符串对象加入到list集合,并且每次循环时让字符串拼接,生成新的字符串。运行之后,过了一点时间后,就会出现异常了。
这里出现的异常信息是“java.lang.OutOfMemoryError: Java heap space”,即Java的堆空间不足导致的内存溢出错误。
此处例子中出现堆内存异常的原因是,这里的List集合是不会被垃圾回收的,因为它一直在作用范围内被用着,而越来越变长的字符串对象也一直被追加到list中,所以随着字符串对象越来越多,堆控件就会被占满了。

网友1:字符串字面量赋值是在方法区中
网友2:这里好像有问题

本人评:此处没必要纠结这些小问题小疑问,重点是大致了解相关概念和相关情况即可。

堆内存诊断

jps工具

查看当前系统中有哪些Java进程,并且把它们的进程编号显示出来。

jmap工具

当用jps工具拿到进程编号之后,可以用jmap工具去查看这个进程在堆内存的占用情况。但是jmap他只能查询某一个时刻的堆内存的占用情况。如果想查看连续的情况,即随着时间的流逝他对堆内存的占用情况的话,就得用下面的。

jconsole工具

图形界面的,多功能的监测工具,可以连续监测。

据说更好的工具jvisualvm

和上面一样,也是图形化界面,监测的好像更多。

简单案例
// 演示堆内存
public class Demo {
	public static void main(String[] args) throws InterruptedException {
		print("1...");
		Thread.sleep(30000);// 打印1后,等待30秒。(主要是留给我一段时间敲那些命令)
		byte[] array = new byte[1024 * 1024 * 10];//10mb 30秒之后,分配了一块儿内存,由于他是用new创建的,所以他占用的是堆空间
		print("2...");
		Thread.sleep(30000);// 打印2后,再等待30秒
		array = null;// 然后把引用给null,意味着这个array变量不会再引用刚才的对象了,即array可以被垃圾回收了
		System.gc();// 垃圾回收
		print("3...");// 回收后输出3(这个时候再检测看看堆内存的变化情况)
		Thread.sleep(1000000L);
	}
}

通过这个案例,目的是要在不同时间点上查看堆内存的占用情况:运行程序后,在本地java文件所在的目录里打开终端,在30秒的时间内输入些命令。

jps

执行后,此例子下,输出了如下信息:

13696 Main
13364
18756 Demo
10040 RemoteMavenServer
16568 Launcher
18168 Jps

在这里就看到了“18756 Demo”。接着执行如下:

jmap -heap 18756

执行后出现一堆信息(稍后解释)。

这时候,过了30秒,所以程序输出2了,然后再30秒之间,继续写命令查看此时的占用情况,亮点是因为刚刚创建了array对象。

jmap -heap 18756

执行后出现一堆信息(稍后解释)。

过了30秒后,array被null,而且垃圾回收了,输出3之后,再检测一遍。

jmap -heap 18756

以上是在三个时间点上分别监测了一下,也就是在三个时间点,抓去了内存的快照信息,大概结果如下:

在第一次输出的内容中,可以看到“Heap Useage:”部分,这里就是显示堆内存的占用情况。里面有“Eden Space:”区域是指新创建的对象使用的区域(比如这里的array),但此时的信息是创建array对象之前的信息,所以这时候还没有array,然后看到这个区域的used项显示使用的是6MB,而总容量(capacity项)是64MB,这个是第一个时间点的信息。

第二次输出的内容是创建byte数组对象之后的情况,在这次的输出内容中,再找到“Heap Useage:”部分,再看一下他的“Eden Space:”区域,可以看到里面的used项显示内存使用了16MB,比刚才多了10MB,因为新创建的数组大小就是10MB。

第三次输出内容是等垃圾回收之后的内存快照信息,在输出内容中,可以看到“Eden Space:”区域的used项的值是1MB,这说明执行垃圾回收之后,刚才16MB中的不用的垃圾都被回收掉了,包括array这个10MB的对象。

还可以使用图形化工具jconsole或jvisualvm(好像更好)动态时时
查看相关内存占用情况,因为本人感觉没必要特意整理这些,所以就算
了。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值