JVM-内存结构(2)

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

本地方法栈

本地方法就是Java调用非Java代码的API,因为JAVA有时候没法直接和操作系统底层交互,所以需要用到本地方法(线程私有)。

本地方法栈管理着本地方法的调用,在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一

通过new关键字创建的对象都会被放在堆内存

所有线程都共享堆,堆内存中的对象都需要考虑线程安全问题

有垃圾回收机制(Minor GC、Major GC、Full GC)

堆里面的内存并不是都共享的,还有TLAB(线程私有的缓存区),用于提高线程同步的并发性。

堆的内存分布?

在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常分为下面三部分:

  1. 新生代(Young Generation):又可分为Eden+Survivor空间
  2. 老生代(Old Generation)
  3. 永久代(Permanent Generation)

而JDK8 以后,永久代变成了元空间(在方法区里面)

  • 几乎所有的对象都是在Eden区被new出来的(如果对象过大,可能直接进入老年代)
  • 从Eden->Survivor->老年代:都是发生GC的过程

Java对象都是在堆上分配吗

  • 不一定,未逃逸出当前函数的指针指向的对象可以在栈上分配
  • 但是HotSpot虚拟机目前说这个逃逸分析算法还不成熟,因此都是在堆上分配

方法区

方法区是一个概念,永久代和元空间都是其实现。

1.6JDK

  • 静态变量、字符串常量池都在永久代中

1.7JDK

  • 将静态变量、字符串常量池存放在堆中(主要是因为永久代(方法区实现)的 GC 回收效率太低,只有在整堆收集 (Full GC)的时候才会被执行 GC。Java 程序中通常会有大量的被创建的字符串等待回收,将字符串常量池放到堆中,能够更高效及时地回收字符串内存。)

1.8JDK

  • 字符串常量池在堆中
  • 方法区也是线程共享的,其存储着类相关信息(类型信息、静态变量、运行时常量池等)
  • JDK1.8,元空间已经不占用堆内存了(不由JVM管理),而是移出到本地内存当中(操作系统内存,且默认没有设置上限内存)

永久代为什么要被元空间代替?

  • 对永久代调优困难(full GC很浪费时间)
  • 永久代的空间大小难设置(导致动态加载类时,容易产生OOM)

猜你喜欢

转载自juejin.im/post/7124897342079107079