Java - JVM Memory

Java Runtime JVM memory allocaiton

JDK 1.7 模型

java-memory java-memory-3

  1. Stack,栈(每个线程单独一份)
    • Program Counter,程序计数器
    • Java Stack,Java栈,有时也叫VMStack,存放local variables, return values, operand stack
    • Native Method Stack,本地方法栈
  2. Heap,堆
    • 存放Objects
    • 一般占用空间大,所以有GC:Young Generation,Old Generation
  3. Method Area,方法区(别称:Non-Heap,非堆)(改名:Metaspace,元数据区)
    • (约等于)PermGen space 永久代
    • (总体来说,是用来存放 class data)
    • 存放运行时的常量池 (静态常量+动态常量)
      • 静态常量:字面量(Literal) + 符号引用量(Symbolic References,编译概念,如类名,接口名,方法名)
      • 动态常量:jvm在完成类装载操作后,class文件中的常量,一个典型的就是String.intern()
      • 静态变量 static variable
      • 参考 -> Java中静态常量和静态变量的区别 https://blog.csdn.net/luzhensmart/article/details/86855029

JDK 1.8 模型

1.8之前,Method Area 方法区;存在JVM中 1.8之后,Metaspace 元数据区;存在内存中

Why?

java-memory-2

常见OutOfMemoryError演示与分析

java.lang.OutOfMemoryError: Java heap space

java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。 下例中,我们不断new对象出来,导致OOM。

// VM options: -Xms10M -Xmx10M
public class HeapOOM {
  public static void main(String[] args){
      long i= 0;
      try {
          List<Object> objects = new ArrayList<Object>();
          while (true) {
              i++;
              objects.add(new Object());
              System.out.println(i);
          }
      } catch(Throwable ex) {
          System.out.println(i);
          ex.printStackTrace();
      }
  }
}

java.lang.OutOfMemoryError: PermGen space

java永久代溢出,即方法区溢出了,一般出现于大量Class或者JSP页面,或者采用CGLIB等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。

// -XX:MaxPermSize=10M
public class HeapOOM {
  public static void main(String[] args) throws Exception {
      for (int i = 0; i < 100_000_000; i++) {
          generate("cn.paul.test" + i);
      }
  }

  public static Class generate(String name) throws Exception {
      ClassPool pool = ClassPool.getDefault();
      return pool.makeClass(name).toClass();
  }
}

java.lang.StackOverflowError

java栈溢出,一般是由于程序中存在死循环,或者深度递归调用造成的。 下例中,是一个无限的递归。

public class HeapOOM {
  public static void main(String[] args){
     stackOverFlow(new AtomicLong(1));
  }

  public static void stackOverFlow(AtomicLong counter){
      System.out.println(counter.incrementAndGet());
      stackOverFlow(counter);
  }
}

Escape Analysis

什么是逃逸

一个对象(的指针)被多个方法或者线程引用时,那么我们就称这个对象(的指针)的逃逸 Escape 。

什么是逃逸分析

JVM可以对对象进行逃逸分析。

-XX:+DoEscapeAnalysis开启逃逸分析(JDK 6u23以上默认开启)
-XX:-DoEscapeAnalysis 关闭逃逸分析
 
#标量替换基于分析逃逸基础之上,开启标量替换必须开启逃逸分析
-XX:+EliminateAllocations开启标量替换(jdk1.8默认开启,其它版本未测试)
-XX:-EliminateAllocations 关闭标量替换
 
#锁消除基于分析逃逸基础之上,开启锁消除必须开启逃逸分析
-XX:+EliminateLocks开启锁消除(jdk1.8默认开启,其它版本未测试)
-XX:-EliminateLocks 关闭锁消除

参考 -> https://blog.csdn.net/m0_37609579/article/details/105288090

常见提问

1

2

Fork me on GitHub