Java虚拟机-内存tips

java虚拟机内存可以分为独占区和共享区。

独占区:虚拟内存栈、本地方法栈、程序计数器。

共享区:方法区、Java堆(用来存放对象实例)。

Java虚拟机-内存tips

  程序计数器

  比较小的内存空间,当前线程所执行的字节码的行号指示器,如果执行的为java方法,那么计数器记录的是正在执行的虚拟机字节码指令的地址,如果方法是native方法,则为undefined。

  字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器完成。

  在任何一个确定的时刻,一个处理器只能执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各个线程之间的程序计数器互相不影响,独立存储。  

  Java虚拟机栈

  生命周期和线程相同。存放方法时运行的数据,描述的是Java方法执行的动态内存模型。

  栈帧:每次方法执行,就会创建一个栈帧,栈帧进栈就开始执行。如果调用其他方法,则又会创建一个栈帧,就按照栈的先进先出来进行。栈帧用来存储局部变量表、操作数栈、方法出口等。

  局部变量表:存放编译器可知的基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用等,大小不会改变。只有double和long会占用两个局部变量空间,其他只占用一个。局部变量表的大小在编译期间被确定。

  本地方法栈

  本地方法栈的作用和虚拟机栈作用相似,只不过虚拟机栈为Java方法(也就是字节码)服务,本地方法栈为Native方法服务。

  Java堆

  在大多数情况上来说,Java堆是Java虚拟机锁管理的内存中最大的一块。Java堆是被所有进程共享的一块内存区域。Java堆的目的就是存放对象实例,几乎所有的对象实例都要在这分配内存。

  Java堆在虚拟机启动时创建。

  Java堆是垃圾收集器管理的主要区域,所以又称GC堆。Java堆又可以分出来新生代和老年代,再细致一点可以分出来Eden、From Survivor、To Survivor空间。进一步的划分只要是为了更好地利用回收内存。

  Java堆可以处于物理上不连续的区域,只要它们逻辑上是连续的。

  方法区

  方法区用来存放已经被虚拟机加载的类信息、常量、静态变量等。

  在某些虚拟机上(HotSpot),方法区又称为永久代,这样垃圾收集器也可以管理方法区。

  运行时常量池

  运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用来存放编译期生成的各种字面量和符号引用,这部分在类加载后进入方法区的运行时常量池进行存放。

  运行期间也可以将新的常量存放在池中,如String类中的intern方法。

  Hotspot虚拟机在Java堆中全过程

  对象的创建

  虚拟机遇到一条new指令,首先去检查这条指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用是否被加载、解析、初始化过。如果没有,那么必须先执行累的加载过程。

  在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象内存的大小在类加载完成之后便可以确定,为对象分配内存的任务等同于把一块确定大小的内存从Java堆中划分出来(指针碰撞和空闲列表,选择哪种方式由Java堆是否规整决定的)。

  内存分配完之后,虚拟机将分配的内存空间都初始化为零值(不包括对象头)。接下来,虚拟机将要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。

  在以上的工作完成之后,从虚拟机的角度上看,一个新的对象已经诞生了,但是从Java程序的角度看,对象创建才刚刚开始(init方法还没执行,所有字段都还为零),所以一般来说执行new指令之后再执行init方法,这样一个真正可用的对象才算产生出来。

  对象的内存布局

  在Hotspot虚拟机中,对象在内存的存储的布局分为3块:对象头、实例数据、对齐补充。

  对象头中包括两部分,第一部分用于存储对象自身的运行时数据,比如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID,官方称之为Mark Word。考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间中存储更多的信息。

  对象头的另外一部分是类型指针,就是对象指向它的类元数据的指针,从而虚拟机可以通过这个确定该对象是哪个类的实例。如果对象是一个数组,那么对象头中还有一段记录数组长度的数据。

  实例数据是对象真正存储的有效信息,也是代码中所定义的各种类型的字段内容。

  对其补充的作用就是JVM要求对象内存的起始地址必须是8字节的整数倍,所以用来补充保证满足这一个要求。

  对象的访问定位

Java虚拟机-内存tips

上一篇:【JAVA学习】java虚拟机内存配置,-Xss256m -Xms512m -Xmx800m -XX:MaxPermSize=512m


下一篇:Feign使用Hystrix无效原因及解决方法