这里只是站在性能监控和分析的角度分享性能测试工程师最关心的JVM知识
不啰嗦,直接总结
-
栈是线程私有的,堆是线程共享的
-
栈是运行时单位,堆是存储单位
-
栈解决程序运行问题,堆解决数据存储问题
-
栈中存的基本数据类型和堆中对象的引用,堆中存的是对象
-
栈代表了处理逻辑,而堆代表了数据
-
栈空间不足抛出异常:java.lang.*Error
-
堆空间不足抛出异常:java.lang.OutOfMemoryError
监控和分析基本思路
- 栈
线程是cpu的基本执行单元,而线程的执行信息又存储在栈空间里,所以我们对cpu资源的分析核心就是栈数据的分析,也就是经常说的对线程做dump(拍快照)。
cpu常见的瓶颈主要有两种:
-
cpu资源很容易被消耗掉,导致cpu资源利用率超高
-
不管给多大压力,cpu的资源利用率总是上不去
这些问题分析的入口基本都是对栈的分析,所以栈善于分析如下问题:
系统无缘无故CPU过高
系统挂起,无响应
系统运行越来越慢
性能瓶颈,如无法充分利用CPU等
线程死锁、死循环,饿死等
线程数量太多导致系统失败,如无法创建线程等
2.堆
内存泄漏,垃圾回收(GC),这些就是对堆的监控和分析了(当然,堆内存不足的时候也会导致cpu超高的(例如频繁full gc),这是后话了)
.class格式的文件通过JVM运行在不同的操作系统平台上,那么这些程序在JVM里面到底是怎么运行的呢?JVM又有哪些内容组成?哪些又是我们必须掌握的知识呢?
代码执行过程
Java虚拟机内部体系结构
中文对照:
在上图的内存空间(Java Memory Allocation Area)中,对我们来说最核心两块内存区域就是堆(Heap)和栈(Stack)了,这也是咱们监控和分析的重点!
在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。而堆则是所有线程共享的,意思就是所有线程共用一个堆,线程执行过程中所产生的对象都在堆里面扔着呢!
栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。
堆和栈中,栈是程序运行最根本的东西。程序运行可以没有堆,但是不能没有栈。而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。不过,正是因为堆和栈的分离的思想,才使得Java的垃圾回收成为可能。