Java:JVM

1. 运行时数据区域

Java程序运行时,会划分不同的区域。
JDK1.8之前和JDK1.8略有区别,如图。
2

1) 程序计数器

  • 是内存中很小的一块内存空间。
  • 主要作用有两点:
    a. 字节码解释器通过修改程序计数器来依次读取指令,实现代码的流程控制,如顺序执行、选择、循环、异常处理;
    b. 在多线程的情况下,程序计数器用于记录当前线程执行的位置,上下文切换后可找到该线程上次执行到哪了。

注意:程序计数器是唯一一个不会出现OOM的内存区域 ,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。

2) Java虚拟机栈

  • 线程私有的,随着线程的创建而创建,随着线程的结束而死亡;(私有/公有?)
  • Java虚拟机栈描述的是方法执行的内存模型,每次方法调用的数据都是通过栈传递的;(描述的是什么)
  • Java虚拟机栈是由一个一个栈帧构成的,每个栈帧都拥有局部变量表、操作数栈、动态链接、方法出口信息等;(由什么构成)
  • Java虚拟机栈的内存大小不允许动态扩展时,线程调用栈的深度大于虚拟机所允许的深度就会抛出StackOverFlowError;可以动态扩展时,当栈扩展时无法申请到足够内存就会抛出OutOfMemoryError。(抛出Error

扩展:方法/函数如何调用?
Java中的栈可类比数据结构中的栈,Java中保存的主要内容是栈帧。每次方法调用都会有一个对应栈帧压入Java栈,每一个方法调用结束后都会有一个栈帧被弹出。
Java中方法有两种返回方式:

  1. return语句
  2. 抛出异常
    无论哪种方式都会导致栈帧被弹出。

3) 本地方法栈

  • 和虚拟机栈发挥的作用类似。
  • 区别是:虚拟机栈为Java方法(字节码)服务,本地方法栈为虚拟机所使用的Native方法服务;
  • 栈的内容也为栈帧,栈帧同样用于存放本地方法的局部变量表、操作数栈、动态链接、出口信息;
  • 同样会抛出StackOverFlowError和OutOfMemoryError两个错误。

4) 堆

  • 此内存区域唯一的目的就是存放对象实例,几乎所有的对象实例的数组都在这里创建。
  • Java世界中“几乎”所有的对象实例都在堆上创建,但随着JIT编译期的发展和逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术慢慢产生了微妙的变化,都在对上建立慢慢变得不那么绝对了。从JDK1.7开始默认开启逃逸分析技术,当某些方法中的对象引用未被返回或者未被外界使用(未逃逸出去),就可以直接为该对象在栈上分配内存。
  • Java对垃圾回收器管理的主要区域,因此也被称为GC堆。从垃圾回收的角度Java堆可以分为新生代和老年代;再细致一点有Eden空间、from Survivor、to Survivor空间等。进一步划分是为了更好地回收内存。
  • 大部分情况,对象会先在Eden区分配,经过一次回收,如果对象还存活,则进入Survivor区,进入Survivor区后年龄加1,直到年龄加为15(默认),则进入老年代。

5) 方法区

  • 用于存储虚拟机加载后的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  • 相对而言垃圾收集在这个区域是较少出现的,但并不代表这个区域的数据就会“永久存在”。

6) 运行时常量池

  • 运行时常量池是方法区的一部分。
  • Class文件中除了存有类的版本、字段、方法、接口等描述信息外,还存有常量池表。

7) 直接内存

  • 直接内存并不是虚拟机运行时数据区域中的一部分,也不是Java虚拟机规范中定义的内存区域,但这部分内存也被频繁使用。
  • 也可能会导致OutOfMemoryError错误出现。
  • 本级直接内存不会受到Java堆的限制,但既然是内存就会受到本机内存总大小以及处理器寻址空间的限制。

2. Java对象的创建过程(JVM遇到一条字节码new指令时)

Step1 类加载检查
Step2 为新对象分配内存
Step3 初始化内存空间为0
Step4 为对象进行必要的设置

posted @ 2021-08-23 16:06  aguo718  阅读(28)  评论(0编辑  收藏  举报