欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JVM学习笔记(一)---JVM内存区域划分

程序员文章站 2023-04-04 11:23:40
声明:本系列是个人整理自己知识点的过程,一些基本概念不再过多书写,重点是实际操作和结构图的整理 一、JVM内存区域简图 JVM大致划分的这几个区域,有的区域是以线程为单位,而有的区域则是整个JVM进程唯一的。 程序计数器(PC,Program Counter Register) 在JVM规范中,每个 ......

声明:本系列是个人整理自己知识点的过程,一些基本概念不再过多书写,重点是实际操作和结构图的整理

 一、jvm内存区域简图

JVM学习笔记(一)---JVM内存区域划分

jvm大致划分的这几个区域,有的区域是以线程为单位,而有的区域则是整个jvm进程唯一的。

 

程序计数器(pc,program counter register)

  在jvm规范中,每个线程都有它自己的程序计数器,并且任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的java方法的jvm指令地址。如果是在执行本地方法,则是undefined。

 

java虚拟机栈(java virtual machine stack)

  早期也叫java栈。每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧(stack frame),对应着一次次 的java方法调用。在一个时间点,对应的只会有一个活动的栈帧,通常叫作当前帧,方法所在的类叫作当前类。如果在该方法中调用了其他方法,对应 的新的栈帧会被创建出来,成为新的当前帧,一直到它返回结果或者执行结束。jvm直接对java栈的操作只有两个,就是对栈帧的压栈和出栈。

 

本地方法栈(native method stack)

  它和java虚拟机栈是非常相似的,支持对本地方法的调用,也是每个线程都会创建一个。在oracle hotspot jvm中,本地方法栈 和java虚拟机栈是在同一块儿区域,这完全取决于技术实现的决定,并未在规范中强制

 

堆(heap)

  它是java内存管理的核心区域,用来放置java对象实例,几乎所有创建的java对象实例都是被直接分配在堆上。堆被所有的线程共享,在虚拟机启动时,我们 指定的“xmx”之类参数就是用来指定最大堆空间等指标。堆也是垃圾收集器重点照顾的区域,所以堆内空间还会被不同的垃圾收集器进行进一步的细分,最有名的就是新生代、老年代的划分。

 

方法区(method area)

  这也是所有线程共享的一块内存区域,用于存储所谓的元(meta)数据,例如类结构信息,以及对应的运行时常量池、字段、方法代码等。
由于早期的hotspot jvm实现,很多人习惯于将方法区称为永久代(permanent generation)。oracle jdk 8中将永久代移除,同时增加了元数据区(metaspace)。

 

运行时常量池(run-time constant pool)

  这是方法区的一部分。如果仔细分析过反编译的类文件结构,你能看到版本号、字段、方法、超类、接口等各种信息,还有一 项信息就是常量池。java的常量池可以存放各种常量信息,不管是编译期生成的各种字面量,还是需要在运行时决定的符号引用,所以它比一般语言的符号表存储的信息更加宽泛

 

二、逃逸分析

看到过一些关于逃逸分析的文章,jvm会在栈上分配那些不会逃逸的对象,这在理论上是可行的,oracle hotspot jvm中并未 这么做,

escape analysis

escape analysis is a technique by which the java hotspot server compiler can analyze the scope of a new object's uses and decide whether to allocate it on the java heap.

based on escape analysis, an object's escape state might be one of the following:

  • globalescape – an object escapes the method and thread. for example, an object stored in a static field, or, stored in a field of an escaped object, or, returned as the result of the current method.
  • argescape – an object passed as an argument or referenced by an argument but does not globally escape during a call. this state is determined by analyzing the bytecode of called method.
  • noescape – a scalar replaceable object, meaning its allocation could be removed from generated code.

after escape analysis, the server compiler eliminates scalar replaceable object allocations and associated locks from generated code. the server compiler also eliminates locks for all non-globally escaping objects. it does not replace a heap allocation with a stack allocation for non-globally escaping objects.

,所以可以明确所有的对象实例都是创建在堆上。

结论实操验证

package po;

public class d1 {

    private byte i;

    public d1(byte i){
        this.i = i;
    }

}
import po.d1;

public class demo1 {


    public static void main(string[] args) {
        for(int i=0;i<1000000;i++){
            byte b = 1;
            d1 d = new d1(b);
        }
    }
}

JVM学习笔记(一)---JVM内存区域划分

JVM学习笔记(一)---JVM内存区域划分

虽然d变量是未逃逸的对象,但是运行后 heap进行gc,说明它还是创建在堆上的。