JVM之方法区

JVM之方法区

 

方法区放什么

 

对于每一个加载的类型,会在方法区中保存以下信息:

 

  • 类及其父类的全限定名(类的全路径名)(java.lang.Object没有父类)
  • 类的类型(Class or Interface)
  • 访问修饰符(public, abstract, final)
  • 实现的接口的全限定名的列表
  • 常量池
  • 字段信息
  • 方法信息
  • 静态变量
  • ClassLoader引用
  • Class引用

对于每一个字段,会在方法区中保存以下信息(字段声明顺序也会保存):

 

  • 字段名
  • 字段的类型
  • 字段的修饰符(public, private , protected, static, final, volatile, transient)

对于每一个方法,会在方法区中保存以下信息(方法声明顺序也会保存):

 

  • 方法名
  • 方法返回类型(或void)
  • 参数信息
  • 方法修饰符(public, private, protected , static, final, synchronized, native, abstract)

如果方法不是抽象方法并不是本地方法(Native Method),还会保存以下信息:

 

  • 方法的字节码
  • 本地变量表及操作数栈的大小
  • 异常表

 

 

方法区注意的地方

 

  1. 默认64M
  2. 当OutOfMemoryError时,可以修改MaxPermSize
  3. 需要多大的永久代空间,取决于类的数量、方法的大小、常量池的大小

 

 

方法区的缺点

 

它的大小是在启动时固定好的,很难进行优化,-XX:MaxPermSize应该设置多大

 

 

 

方法区特点

 

  • 方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。例如,假如同时有两个线程都企图访问方法区中的同一个类,而这个类还没有被装入JVM,那么只允许一个线程去装载它,而其它线程必须等待 
  • 方法区的大小不必是固定的,JVM可根据应用需要动态调整。同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中自由分配。
  • 方法区也可被垃圾收集,当某个类不在被使用(不可触及)时,JVM将卸载这个类,进行垃圾收集 

 

 

 

对方法区的另一种理解

 

      方法区也是所有线程共享。主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。 关于方法区内存溢出的问题会在下文中详细探讨。

 

 

 

永久代

 

JDK 1.6 还在使用永久代,当类或方法过多,就会导致永久代内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。

 

永久代的满了或者超过临界值,也会触发Full GC,而永久代也会被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。

 

代码

package com.paddx.test.memory;
 
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
 
public class PermGenOomMock{
    public static void main(String[] args) {
        URL url = null;
        List<ClassLoader> classLoaderList = new ArrayList<ClassLoader>();
        try {
            url = new File("/tmp").toURI().toURL();
            URL[] urls = {url};
            while (true){
                ClassLoader loader = new URLClassLoader(urls);
                classLoaderList.add(loader);
                loader.loadClass("com.paddx.test.memory.Test");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

结果

 

 

 

永久代配置

PermSize

MaxPermSize

 

 

元空间

 

JDK1.8放弃了方法区,将其改成元空间,最大的区别是:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

 

内存溢出结果

 

 

 元空间配置

-XX:MetaspaceSize

-XX:MaxMetaspaceSize

-XX:MinMetaspaceFreeRatio

猜你喜欢

转载自youyu4.iteye.com/blog/2353389