一、堆

1、介绍

  Java运行程序对应一个进程,一个进程就对应一个JVM实例。一个JVM实例就有一个运行时数据区(Runtime),Runtime里面,就只有一个堆,一个方法区。这里也阐述了,方法区和堆是一个进程一份。而一个进程当中,可以有多个线程,那就意味着一个进程中的多个线程会共享堆空间和方法区。
  一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。堆在JVM启动的时候被创建,其空间大小也就确定了,是JVM管理的最大一块内存空间,堆内存大小是可以调节的。
  Java虚拟机规范规定,堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。
  所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(TLAB)。

JVM详解(四)——运行时数据区-堆-LMLPHP

  堆空间中,有一部分线程私有的缓冲区,叫TLAB,它不是所有线程共享的区域。

  《Java虚拟机规范》中对堆的描述是:所有的对象实例以及数组都应当在运行时分配在堆上。其实,从实际使用角度来看,是"几乎"所有的对象实例都在这里分配内存。
  数组和对象可能永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或数组在堆中的位置。在方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除。堆,是GC执行垃圾回收的重点区域。而频繁的GC会影响用户线程的执行。
  为什么是几乎?逃逸分析,会去判断在方法中对象是否发生了逃逸,如果没有的话,会在栈上分配。

JVM详解(四)——运行时数据区-堆-LMLPHP

2、堆的内存结构

  堆空间细分

JVM详解(四)——运行时数据区-堆-LMLPHP

  JDK7:

JVM详解(四)——运行时数据区-堆-LMLPHP

  JDK8:

JVM详解(四)——运行时数据区-堆-LMLPHP

  永久代-->元空间

JVM详解(四)——运行时数据区-堆-LMLPHP

3、设置堆内存大小与OOM

  Java堆用于存储Java对象实例,在JVM启动时就已经设定好了。可以通过-Xmx和-Xms来进行设置。一旦堆区的内存大小超过-Xmx所指定的最大内存时,将会抛出OutOfMemoryError异常。

  通常会将-Xms和-Xmx两个参数配置相同的值,其目的是为了能够在Java垃圾回收机制清理完堆区后不需要重新分割计算堆区的大小,从而提高性能。
  理由:初始设置一个值之后,如果堆空间不够的话,需要不断的扩容。后续不用的话,也需要释放。那么,在服务器使用的时候,堆空间不断的扩容。在空闲的时候,也需要把堆空间做释放,那频繁的扩展和释放,会造成不必要的系统压力。
  默认情况下,初始内存大小:物理电脑内存大小/64。最大内存:物理电脑内存大小/4。
  代码示例:设置堆内存大小

 1 // 默认情况
 2 public class Main {
 3     public static void main(String[] args) {
 4
 5         // 返回Java虚拟机中的堆内存总量
 6         long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
 7         // 返回Java虚拟机试图使用的最大堆内存量
 8         long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
 9
10         System.out.println("-Xms : " + initialMemory + "M");
11         System.out.println("-Xmx : " + maxMemory + "M");
12
13         System.out.println("系统内存大小为:" + initialMemory * 64.0 / 1024 + "G");
14         System.out.println("系统内存大小为:" + maxMemory * 4.0 / 1024 + "G");
15
16 //        try {
17 //            Thread.sleep(1000000);
18 //        } catch (InterruptedException e) {
19 //            e.printStackTrace();
20 //        }
21     }
22 }
23
24 // 默认值
25 // -Xms : 245M (约为 16G / 64)
26 // -Xmx : 3628M
27 // 系统内存大小为:15.3125G (这个值约等于系统内存)
28 // 系统内存大小为:14.171875G
29
30 // 设置堆参数:-Xms600m -Xmx600m
31 // -Xms : 575M
32 // -Xmx : 575M
10-18 19:25