jvm内存
jvm-虚拟机 -内存
虚拟机相关知识可能是理论大于实践的,在实际工作中涉及的机会比较少。但是也是必须要了解的知识。 为啥要学虚拟机可以写出更好、更健壮的Java程序 提高Java应用的性能,排除问题 面试 jvm运行时数据区域方法区:永久区,用于存储已经被虚拟机加载的类信息,常量 ("abc","123"等),静态变量(static变量)等数据(-XX:PermSize;- XX:MaxPermSize;-XX:MetaspaceSize; -XX:MaxMetaspaceSize ) 。 堆:Java需要重点关注的一块区域,因为涉及到内存的分配 (new关键字,反射等)与回收(回收算法,收集器等) (-Xms;-Xmx; -Xmn;-XX:NewSize;-XX:MaxNewSize) ; 栈:线程私有,生命周期和线程,每个方法在执行 的同时都会创建一个 栈帧 用于存储局部变量表,操作 数栈,动态链接,方法出口等信息。方法的执行就对 应着栈帧在虚拟机栈中入栈和出栈的过程;栈里面存 放着各种基本数据类型和对象的引用(-Xss) ; 程序计数器:较小的内存空间,当前线程执行的字节 码的行号指示器;各线程之间独立存储,互不影响; 本地栈方法:本地方法栈保存的是native方法的信息, 当一个JVM创建的线程调用native方法后,JVM不再为 其在虚拟机栈中创建栈帧,JVM只是简单的动态链接 并直接调用native方法; 直接内存 运行时常量池:运行时常量池是方法区的一部分,用于存放编译期生成 的各种字面量("abc","123"等)和符号引用。
下面是jdk1.6 ~ jdk 1.8 jvm内存示意图。
上面的内存区域也可以分为线程独享和共享 独享:虚拟机栈、本地方法栈、程序计数器 共享:堆、方法区
直接内存 :不是虚拟机运行时数据区 的一部分,也不是java虚拟机规范中定 义的内存区域。 如果使用了NIO,这块区域会被频繁使用,在java堆内可以用 directByteBuffer对象直接引用并操作; 这块内存不受java堆大小限制,但 受本机总内存的限制,可以通过 MaxDirectMemorySize来设置(默认 与堆内存最大值一样),所以也会 出现OOM异常; 堆和栈区别栈是以栈帧的方式存储调用的过程, 并存储方法调用过程中基本数据类型的变量(int、short、long、byte、float、double、boolean、char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放;而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中; 栈是线程独享的,每个线程都会创建一个自己的栈。而堆内存中的数据可以被多个线程访问 栈大小远小于堆大小 public class Test1 { private String name; private int id; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public Test1(String name, int id) { this.name = name; this.id = id; } public static void main(String[] args) { Test1 t1 = new Test1("非鸽传书",1); Test1 t2 = new Test1("学无止境",2); System.out.println(t1.getName()); System.out.println(t2.getName()); } }
我们来分析下上面程序中执行main方法,jvm内存情况。 Test1类的信息放在方法区中 new出来的信息放在堆中(t1, t2) 栈中存放指针指向t1、t2
方法的入栈和出栈
方法会打包成栈桢,一个栈桢至少要包含局部变量表,操作数栈和帧数据区.
栈是先进后出,每个打包成栈帧的方法执行时会压入栈中,执行完后弹出。下面为示意图
这里有一个栈上分配的情况,本次先不学习,留一个尾巴,后面在搞。
虚拟机中对象访问的定位 使用句柄这里就涉及一个句柄池的虚拟概念,实际上就是一个引用指针指向堆或者方法区中的对象。而栈中的引用指向这个句柄。 使用直接指针,顾名思义就是直接执行对象的
区别就是,使用直接指针访问效率更高,而使用句柄在对象地址变化的时候处理方便。