JVM内存分为: 堆、虚拟机栈、本地方法栈、方法区(永久代、元空间)、程序计数器(PC寄存器)
(方法区和堆是线程共享的,其他都是一个线程创建一个实例)
程序计数器:
-
存储即将要执行的指令代码的地址,由执行引擎读取后执行。
-
每个线程都有自己的程序计数器(线程私有)
-
唯一一个在JVM规范中不会溢出的区域
虚拟机栈:
每个线程创建时都会创建一个虚拟机栈(与线程生命周期一致),内部保存一个个栈桢,每个方法对应一个栈桢(存放方法的局部变量、部分结果,参与方法调用与返回)
本地方法栈:
用于管理本地方法调用,是线程私有的;
JVM没明确规定,不是所有的JVM都支持本地方法栈,在Hotspot JVM中 本地方法栈和虚拟机栈合二为一;
方法区:
-
jdk8之前称为永久代(存储在JVM中),jdk8及以后是元空间
-
在jdk6及之前的永久代中存储 类型信息、域信息、方法信息、JIT代码缓存、静态变量
和运行时常量池(放有String Table):具有动态性,常量不一定是编译时确定,运算时生成的常量也会存在这个常量池中,若创建类或接口的运行时常量池时,所需空间超过方法区大小会报OutOfMemoryError错误,
jdk7把其中的静态变量、运算时常量池中的String Table 放到了堆中
jdk8把永久代放到了本地内存中并改名为元空间
-
方法区的垃圾回收主要回收两部分:常量池中废弃的常量和不再使用的类型
堆:
-
所有线程都共享的一块内存,JVM启动时创建,几乎所有对象实例都在堆中创建,GC执行垃圾回收的重点区域
-
根据GC执行原理,堆的内存逻辑上分为三部分:新生区(又分为Eden区、Surivivor区)、养老区、永久区(jdk8及以后:元空间)
-
GC回收分为 Minor GC、Major GC、FullGC,
-
当新生区的Eden代满时会触发 Minor GC清理内存,Minor GC触发频繁,回收速度也较快,会触发STW,暂停其他用户线程,等垃圾回收结束后,用户线程才会恢复
-
Major GC 发送在老年代,速度比Minor GC慢10倍以上(STW时间更长)在老年代空间不足时,会先尝试触发Minor GC,若还是空间不足就会触发Major GC,若Major GC后内存还不足就会报OOM
-
Full GC执行的情况:①调用System.gc()时,系统建议执行Full GC(不是必然执行)、②老年代空间不足、③方法区空间不足、④通过Minor GC进入老年代的平均大小大于老年代可用内存、⑤Eden区、survivor space0 向 suriivor space1 (from 向to)区复制时,对象大小大于 to 区 可用内存,将对象转存到老年代,老年代可用内存小于该对象大小时 【Full GC 在开发、调优中是要尽量避免的(暂时时间可以短一些)】
-