堆是JVM中相当核心的内容,因为堆是JVM中管理的最大一块内存区域,大部分的GC也发生在堆区,那接下来就让我们深入地探究一下JVM中的堆结构。
需要明确,一个JVM实例只存在一个堆内存,堆区在JVM启动的时候就被创建,其空间大小也被确定下来,但堆空间的大小是可以通过JVM参数调节的,所有的线程共享堆。
堆的内存结构
因为堆是垃圾回收的重点区域,现代垃圾回收器大部分都基于分代收集理论设计,所以将堆空间分为:
Young Generation Space(新生代)
Old Generation Space(老年代)
Perm Space(永久代)- 永久代是方法区的一个实现(只有HotSpot JVM才有永久代),事实上方法区是逻辑独立的,即:从逻辑上来说,方法区是在堆的外面的
其中新生代又可细分为:
Eden(伊甸园区)
Survivor(幸存区)
![](https://i-blog.csdnimg.cn/blog_migrate/444088218b9442d8c3187fdf454aab8b.jpeg)
从JDK1.8开始,JVM规范摒弃了方法区的概念,取而代之的是Meta Space(元空间),使用的是物理内
存。
![](https://i-blog.csdnimg.cn/blog_migrate/ac116a1e2c42f4b5420be2b66fcab8e1.jpeg)
通过两个JVM参数可以设置堆的初始内存和最大内存:
-Xms:设置堆的初始内存
-Xmx:设置堆的最大内存
我们可以先来看看自己的JVM分配的堆内存情况:
public static void main(String[] args) {
// 获取堆空间的内存总量
long totalMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
// 获取堆空间试图使用的最大内存
long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
System.out.println(totalMemory + "M");
System.out.println(maxMemory + "M");
}
运行结果:
123M
1799M
默认情况下堆的初始内存大小是物理内存的64分之一,而最大内存大小是物理内存的四分之一,但是会发现,物理内存(8G)的四分之一应该是2G才对,而堆的最大内存空间并没有到达2G,这个问题我们留到后面解决,先来设置一下堆的内存大小:
在VM options中填入 -Xms600m -Xmx600m
,若是找不到VM options,则点击右上角的Modify options,并勾选Add VM options,此时重新运行程序,结果为:
575M
575M
接下来我们来详细地分析一下堆的内存分配情况,打开cmd窗口,输入 jps
指令可以查看当前正在运行的Java程序,所以改造一下刚才的程序:
public static void main(String[] args) {
while (true){
}
}
一直让它运行着,然后输入 jps
:
C:\Users\Administrator>jps
1860 TestDemo
10664 Jps
2568 Launcher
8200
这样便查询到了TestDemo程序的进程id,然后通过该id查询内存分配情况,输入 jstat -gc 1860
ÿ