JVM常见问题(自我整理向)

JVM的内存模型和分区 详细到每个区的作用
Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念。java内存模型中分为主内存和工作内存。主内存里面存储着所有变量,主内存是共享内存区域,所有线程都可以访问。每一个线程都私有一个工作内存,工作内存里面保存着主内存里面变量值的副本,线程对变量的操作都是在工作内存中完成,操作结束后再放回主内存。主内存可粗略认为是堆,工作内存认为是栈。操作系统中,一般CPU都会从内存取数据到寄存器,然后进行处理,但由于内存的处理速度远远低于CPU,导致CPU在处理指令时往往花费很多时间在等待内存做准备工作,于是在寄存器和主内存间添加了CPU缓存,CPU缓存比较小,但访问速度比主内存快得多。Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间。
jvm管理的内存区域包括以下几个区域:
栈区:

栈分为java虚拟机栈和本地方法栈

  1. 重点是Java虚拟机栈,它是线程私有的,生命周期与线程相同。

  2. 每个方法执行都会创建一个栈帧,用于存放局部变量表,操作栈,动态链接,方法出口等。每个方法从被调用,直到被执行完。对应着一个栈帧在虚拟机中从入栈到出栈的过程。

  3. 通常说的栈就是指局部变量表部分,存放编译期间可知的8种基本数据类型,及对象引用和指令地址。局部变量表是在编译期间完成分配,当进入一个方法时,这个栈中的局部变量分配内存大小是确定的。

  4. 会有两种异常StackOverFlowError和 OutOfMemoneyError。当线程请求栈深度大于虚拟机所允许的深度就会抛出StackOverFlowError错误;虚拟机栈动态扩展,当扩展无法申请到足够的内存空间时候,抛出OutOfMemoneyError。

  5. 本地方法栈 为虚拟机使用到本地方法服务(native)

堆区:

  1. 堆被所有线程共享区域,在虚拟机启动时创建,唯一目的存放对象实例。

  2. 堆区是gc的主要区域,通常情况下分为两个区块年轻代和年老代。更细一点年轻代又分为Eden区,放新创建对象,From survivor 和 To survivor 保存gc后幸存下的对象,默认情况下各自占比 8:1:1。

  3. 会有异常OutOfMemoneyError

方法区:

  1. 被所有线程共享区域,用于存放已被虚拟机加载的类信息,常量,静态变量等数据。被Java虚拟机描述为堆的一个逻辑部分。习惯是也叫它永久代(permanmentgeneration)

  2. 垃圾回收很少光顾这个区域,不过也是需要回收的,主要针对常量池回收,类型卸载。

  3. 常量池具有一定的动态性,里面可以存放编译期生成的常量;运行期间的常量也可以添加进入常量池中,比如string的intern()方法。

程序计数器:

  1. 当前线程所执行的行号指示器。通过改变计数器的值来确定下一条指令,比如循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。

  2. Java虚拟机多线程是通过线程轮流切换并分配处理器执行时间的方式实现的。为了线程切换能恢复到正确的位置,每条线程都需要一个独立的程序计数器,所以它是线程私有的。

  3. 唯一一块Java虚拟机没有规定任何OutofMemoryError的区块

  • 堆里面的分区有哪些?说说他们的特点
    堆内存分为三部分:

新生区

养老区

永久区(JDK8后又叫元空间)

在这里插入图片描述

(图片来源于网络)

其中新生区又可进一步分为伊甸区和幸存0区以及幸存1区.

新对象总是在伊甸区中生成,当伊甸区的内存用完时,而此时程序又生成了新对象,这时触发GC机制,JVM对垃圾回收进行轻GC,然后将剩余的对象移至幸存0区,当幸存0区也满了时,再进行一次轻GC,将所有剩余对象移至幸存一区,(注意,幸存一区和幸存0区是交替使用,总有一个区是空的,用于将对象移动到此处),当幸存一区满了时,再GC将对象已知养老区,如果养老区满了,这时就会发生重GC,如果执行完重GC后,养老区依然无法存储新对象,这是程序就会报错(OOM)。

(GC在新生区发生地比较频繁。当每次对象从伊甸区复制到幸存区或者从幸存区中的一个复制到另外一个,有一个计数器会自动增加值。默认情况下,如果复制发生超过16次,JVM会停止复制并把他们移动到养老区去。)

posted @ 2021-10-09 23:51  ymw385  阅读(67)  评论(0)    收藏  举报