首先说下类的记载
类加载的五个过程
加载:类加载器获二进制字节流,将静态存储结构转化为方法区的运行时数据结构,并生成此类的Class对象。
验证:验证文件格式、元数据、字节码、符号引用,确保Class的字节流中包含的信息符合当前虚拟机的要求。
准备:为类变量分配内存并设置其初始值,这些变量使用的内存都将在方法区中进行分配。
解析:将常量池内的符号引用替换为直接引用,包括类或接口的解析、字段解析、类方法解析、接口方法解析。
初始化:执行类中定义的Java程序代码(字节码)。
类的生命周期(7个):加载、验证、准备、解析、初始化、使用、卸载
1、堆区
堆区是JVM中最大一块内存区域,存储着各类生成的对象、数组等,JVM8中把运行时常量池、静态变量也移到堆区进行存储。堆区被细化可以分为年轻代、老年代,而年轻代又可分为Eden区、From Survivor、To Survivor三个区域,比例是8:1:1。一个对象从生成到结束将会有机会经历堆区的不同区域完成“使命”。根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样。在实现时,既可以实现成固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常
问题:什么是运行时常量池?
简单的来class文件在编译后除了存储一些类的版本、字段、方法、接口等元数据信息外,还有一部分信息是常量池,这个常量池我们称之为“静态常量池”,只是作为一种持久化数据存储在硬盘上,代表编译期生成的各种字面量和符号引用(最常见的就是字符串常量),那么这类信息被加载到内存中就会以运行时常量池的形式存在内存中,JDK7以前这类信息被存储在方法区,但是JDK7/JDK8都已经移到了堆区。这类数据变量的好处简单来说就是如果堆区中已经存在一个数据变量,即使再创建一个这样的变量,那么JVM将会直接指向已经创建好的数据,而不会再分配内存区域,这样一方面加快数据的创建,另一方面节省内存空间!但是实际上的机制要复杂一些,可以参考String类去理解!
2、方法区
方法区主要是存储类的元数据的,如虚拟机加载的类信息、编译后的代码等。JDK8之前方法区的实现是