JVM-Java虚拟机


JVM基本内容介绍


介绍下Java内存区域

所有线程共享的内存区域,几乎所有对象实例及数组来这里分配内存

对象在Eden区分配 在一次新的垃圾回收之后,如果对象还在,则(进入s0或者s1,并且对象年龄加1,当年龄达到一定程序(默认15),可通过

-xx:MaxTenuringThreshold 来设置

动态年龄:Hotspot便利所有对象时,按照年龄从小到大对其所占用的大小进行累计,当累计的某个年龄大小找过surrvivor区的一半,取这个年龄和MaxTenuring Threshold 中更小的一个值,作为新晋升年龄值域,参与下一次垃圾回收。

方法区(JDK8之后为元空间)

存储已被虚拟机加载的类信息常量,静态变量,即时编译器编译后的代码数据。

虚拟机栈

  1. 由栈帧组成

1.stackoverFlowError :请求深度超过当前Java虚拟机栈的最大深度
2.outOfMemoryError: 如果虚拟机栈可扩展,无法申请到足够的内存

  • 方法和函数如何调用?
    每次函数调用都会有一个栈压入,调用结束后,都会有一个栈帧被弹出
  • Java有两中方式返回
    1.return
    2.执行异常

本地方法栈

native 方法

程序计数器

  1. 字节码解释器通过改变程序计数器来依次读取指令,从而实现流程控制
  2. 在多线程情况下,程序计数器用来记录当前线程执行的位置
    唯一一个不会出现OOM的内存区域,随线程创建而创建,随线程死亡而死亡

元空间

-XX:MetaspaceSize=N //设置 Metaspace 的初始(和最小大小)
-XX:MaxMetaspaceSize=N //设置 Metaspace 的最大大小

与永久代不同,如果不指定内存,可能会耗尽所有系统内存

常见问题

  1. 为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?
  • 整个永久代有一个 JVM 本身设置固定大小上限,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。
  • 元空间里面存放的是类的元数据,这样加载多少类的元数据就不由 MaxPermSize 控制了, 而由系统的实际可用空间来控制,这样能加载的类就更多了。
  • 在 JDK8,合并 HotSpot 和 JRockit 的代码时, JRockit 从来没有一个叫永久代的东西, 合并之后就没有必要额外的设置这么一个永久代的地方了。

创建对象的过程

1.类加载检查

虚拟机遇到一条new 指令时,首先检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有先执行相应的类加载过程。

2.分配内存

3.初始化零值

4.设置对象头

5.执行init方法