话很少说,干就完了。java
方法区同Java堆同样,也是线程共享区域。方法区主要存储已经被虚拟机加载的类信息(包括类的名称、方法信息、字段信息)、常量、静态变量、即时编译器编译后的代码(好比spring 使用IOC或者AOP建立bean时,或者使用cglib,反射的形式动态生成class信息等)等数据。spring
不少人又把方法区称为"永久代",其实这个说法并不等价。仅仅是由于HotSpot虚拟机选择把GC分代收集拓展到方法区,或者说是使用永久代来实现方法区而已。对于其余的虚拟机来讲是不存在永久代的概念的。线程
方法区除了和堆同样能够不须要连续的内存,也能够选择固定的大小或者动态拓展,还可以选择是否实现垃圾收集。垃圾收集相对来讲在方法区会比较少的出现。较少的出现并不意味着不会出现垃圾收集内存回收的状况,方法区的垃圾收集主要是针对常量池的回收和类型的写在。指针
若方法区没法知足内存分配需求时,会抛出OOM异常。cdn
运行时常量池是属于方法区的一部分,一般存储的是在编译期所产生的字面量及符号引用,以下图所示:对象
在说到类加载子系统时,类的加载由加载、连接(验证、准备、解析)、初始化、使用等这么几个阶段,而在类加载阶段,主要作了如下几件事情:blog
可是须要特别说明的是,类加载阶段所产生的类对象和实例对象本质上是有区别的。类对象仅仅是在类加载的时候生成到内存中的对象,而实例对象通常是经过new关键字所建立的对象。它们的内存存储区域也不同。在上述步骤2中,所谓静态存储结构加载到运行时数据区中其实际上就是将class常量池中的内容保存到运行时常量池中。内存
常量池中还保存这符号引用,在类的解析阶段,会将这些符号引用转换成直接引用(直接指向对象实例的指针地址)保存到常量池中。因此,在整个类加载阶段,有两个环节会将数据保存至常量池中。字符串
运行时常量池相对于类常量池另外一个重要的特征就是具有动态性,Java并不要求常量必定要在编译器就产生,也就是说并非必定要在class常量池中的内容才可以进入到运行时常量池,在程序运行期间,也可能将常量放入到常量池中。例如String类的intern()方法。编译器
常量池属于方法区的一部分那么也是线程共享的,既然内存区域是共享的,那么某种程度上就减轻了新对象频繁建立销毁的内存开销,实现对象的共享。
例如字符串常量池:把全部字符串常量放到一个常量池中
运行时常量池属于方法区的一部分,因此同方法区同样,当出现内存不足时,也会出现OOM异常。
不怕路歹行不怕大雨淋,心上一字敢 面对个人梦,甘愿来做憨人。 --<憨人>