本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本地方法栈
本地方法就是Java调用非Java代码的API,因为JAVA有时候没法直接和操作系统底层交互,所以需要用到本地方法(线程私有)。
本地方法栈管理着本地方法的调用,在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一
堆
通过new关键字创建的对象都会被放在堆内存
所有线程都共享堆,堆内存中的对象都需要考虑线程安全问题
有垃圾回收机制(Minor GC、Major GC、Full GC)
堆里面的内存并不是都共享的,还有TLAB(线程私有的缓存区),用于提高线程同步的并发性。
堆的内存分布?
在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常分为下面三部分:
- 新生代(Young Generation):又可分为Eden+Survivor空间
- 老生代(Old Generation)
- 永久代(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)