即:
类信息存储在方法区
实例对象信息放在Java堆区
引用放在Java栈区
《Java虚拟机规范》:尽管在所有的方法区在逻辑上是属于堆的一部分,但是一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。
对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。
方法区看作是一块独立于Java堆的内存空间
方法区在JDK7之前:永久代
JDK8 :元空间
永久区 与 元空间 区别:
元空间不在虚拟机设置的内存中,而是使用本地内存
JDK7:
-XX:PermSize来设置永久代初始化空间大小,默认值20.75
-XX:MaxPermSize来设置永久代最大可分配空间,32位:64M,64位:82M
JDK8:
-XX:MetaspaceSize 21M
-XX:MaxMetaspaceSize -1,没有限制
CMD查看:
JDK7
jps:查看进程号
jinfo -flag PermSize 正在运行的Java线程号,JDK7
jinfo -flag MaxPermSize 正在运行的java线程号
JDK8:
直接将名字换一换就好了
如果不指定大小,虚拟机会耗尽所有的可用系统内存
当方法区装满了,那么就会触发Full GC清除一部分没用的类,然后适当的扩充方法区空间
尽量将MetaspaceSize设置一个较高的值,避免频繁的GC
内存溢出:没有发生内存泄漏,简而言之就是不够大
增大就完事了
具体存储内容:类型信息、常量、静态变量、即时编译器编译后的代码缓存
对每个加载的类型(类Class、接口interface,枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:
JVM必须在方法区中保存类型的所有域的相关信息以及域的声名顺序
域的相关信息包括:域名称、域类型、域修饰符(public,private,protected,static,final,volatile,transient的某个子集)
JVM必须保存所有方法的以下信息,同域信息一样包含在声名顺序:
javap -v -p class文件名 > test.txt
静态变量和类关联在一起,随着类的加载而加载,它们成为类数据在逻辑上的一部分。
类变量被类的所有实例共享,即使没有类实例时也可以访问它
运行时常量池============》方法区
常量池=================》类字节码文件
包含:
数量值
字符串值
类引用
字段引用
方法引用
一个java源文件中的类、接口,编译后产生一个字节码文件。而Java中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里
但是:
可以将这些数据存到常量池中,这个字节码包括了执行常量池的引用。在动态链接的时候会用到运行时常量池
常量池,可以看作一张表,虚拟机指令根据这张常量表找打要执行的类名,方法名,参数类型,字面量等类型
运行时常量池时方法区的一部分
· 常量池中的(字面量、符号引用),当类加载后存放在方法区的运行时常量池中
加载类和接口到虚拟机后,就会创建对应的运行时常量池
JVM为每个已加载的类型(类或者接口)都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。
运行时常量池中包含了多种不同的常量,包括编译器就已经明确的数值字面量,也包括到运行期解析后才能获得的方法或者字段引用。此时不再是常量池中的符号地址,这里换位真实地址
运行时常量池:相对于Class文件常量池令一重要特征是:具备动态性
运行时常量池似于传统编程语言中的符号表,但是它包含的数据却比符号表更加丰富一些
当创建类或者接口的运行时常量池时,如果构造运行时常量池所需的内存空间朝超过了方法区所能提供的最大值,则JVM抛出OOM
原文:https://www.cnblogs.com/sicheng-li/p/12996749.html