JVM相关知识

运行程序时JVM中内存区域的划分:

线程私有:

本地方法栈:

本地方法栈与虚拟机栈相似,区别是,本地方法栈为虚拟机使用的本地方法服务,虚拟机栈为虚拟机使用的JAVA方法服务。

虚拟机栈:

虚拟机栈中保存的主要是一个个栈帧,每当有一个方法被调用时,都会有栈帧入栈,方法结束时,栈帧就会被弹出,每个栈帧由局部变量表和操作数栈,动态连接,返回地址组成,
局部变量表:存放的方法中的局部变量,局部变量是基本数据类型的话直接存储到表中,如果是引用数据类型的话,则会存入对象引用(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)换言之,除了基本数据类型外,其余的数据类型都是对象的引用?
如int[] 等数组类型,其本质也还是对象。
操作数栈:用于存储方法中计算的中间结果,计算过程中产生的临时变量。
动态链接:当本方法调用其他的方法(其他方法的信息存储在方法区中)时,需要将常量池(方法区也就是元空间中的运行时常量池)中指向方法的符号引用转为在内存地址中的直接引用,而动态链接会将符号引用转化为直接引用。

返回地址:代表的是方法的出口,当方法运行结束后方法的返回地址。

程序计数器:

程序计数器是较小的内存空间(或许是无上限的),主要有两个功能,第一,当程序运行时,字节码解释器通过改变程序计数器读取指令,实现循环,分支,跳转,异常处理等功能。
第二,当线程切换时,可以为程序记录当前线程的执行位置。

线程共享的有:

堆:

最主要的是存放几乎所有的对象实例,几乎所有的对象实例以及数组都在这里分配内存。至于说几乎,是因为存在方法逃逸,当方法中的对象引用没有被返回或者未被外边使用,可以直接在栈上分配内存。在1.7之前堆内存主要分为新生代,老年代和永久代,在1.8之后永久代被元空间取代,元空间在本地内存中。对象首先会在eden区中分配,在一次新生代垃圾回收后,如果对象还存活,则会转入s0或s1区。(Eden 区->Survivor 区后对象的初始年龄变为 1),当年龄增加到一定程度,默认15,就会被晋升到老年代。
在堆中还包含一个字符串常量池:
字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。JDK1.7 之前,字符串常量池存放在永久代。JDK1.7 字符串常量池和静态变量从永久代移动了 Java 堆中。(静态变量?不是在方法区嘛。暂时记为静态变量在元空间中)将字符串常量池放入堆中是因为永久代(方法区的实现)回收效率低,只有在FULL GC时才会被回收,移入堆中可以更高效及时地回收字符串内存。

方法区(在1.8之后改为永久代并移入到直接内存中。)

是一块逻辑区域,各个线程共享的内存区域。当虚拟机需要使用一个类时,需要读取Class文件并获得相关信息,再将信息存储到方法区中。方法区会存储已被虚拟机加载的类信息,静态变量,常量,字段信息,方法信息等。
在方法区中包含一个运行时常量池,在运行时常量池中会有常量池表,这个表中包含编译器时生成的各种字面量和符号引用。字面量包括整数、浮点数和字符串字面量。(栈中的动态链接处)常见的符号引用包括类符号引用、字段符号引用、方法符号引用、接口方法符号。功能类似于传统编程语言的符号表。

两个概念

直接内存:直接内存并不是虚拟机运行时数据区的一部分,是一种特殊的内存缓冲区,并不在 Java 堆或方法区中分配的,而是通过 JNI 的方式在本地内存上分配的。
堆外内存:堆外内存就是把内存对象分配在堆(新生代+老年代+永久代)以外的内存,这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。

你可能感兴趣的:(jvm,java,开发语言)