方法区域Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态方法、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来
对于习惯在HotSpot虚拟机上开发、部署程序的开发者来说,很多人都更愿意把方法区成为“永久代”,本质上两者是不等价的,仅仅是因为HotSpot虚拟机的设计团队把GC分代收集扩展至方法区,或者说使用永生代来实现方法区而已,这样HotSpot虚拟机的垃圾回收器可以像管理Java对堆一样管理这部分内存,能够省去专门为这些方法区编写内存管理代码的工作。原则上如何实现方法区属于虚拟机实现细节,不受虚拟机规范的要求,但是用永生代来实现方法区,现在并不是一个好主意,因为这样更容易遇到内存溢出的问题(永生代有-XX:MaxPermSize 的上限,J9和JRockit只要没有触碰到进程可用内存的上限,例如32位系统中的4GB,就不会出现问题),而且有极少数方法会因为这个原因导致不同虚拟机下有不同的表现。因此,对于HotSpot虚拟机,根据官方发布的路线图信息,现在也有放弃永久代并逐步采用Native Memory来实现方法区的规划了,在目前已经发布的JDK 1.7的HotSpot中,已经把原来放在永久代的字符串常量池移除。
Java虚拟机规范对方法的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说,这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是必要的。在SUN公司的BUG列表中,曾出现过的若干个严重的BUG就是由于低版本的HotSpot虚拟机对此区域未完全回收而导致内存泄漏。
根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
参考《深入理解Java虚拟机》