Person p = new Person();
方法区可以看作是一个独立于堆的内存空间,非堆。方法区和堆一样,是线程共享的,方法区的大小决定了可以存放多少类。如果类加载过多,同样会内存溢出。
jdk1.7以前 成为永久代;1.8后,成为元空间。有本质上的区别,永久代使用的虚拟机内存,而元空间(即方法区)使用的是本地内存。
4.1 方法区大小设置
-XX:MetaspaceSize=100m -XX:MaxMetaspaceSize=100m
默认情况下 最小为21m 最大为-1 表示没有限制
建议将MetaspaceSize设置为一个较高的值,如果初始值较低,实际内存大小一旦超过就会引发Full GC,影响性能。
内存泄漏:对象已经失效,但是和引用之间的关联没有断开,导致GC时无法回收空间。
内存溢出:生成对象所用的实际大小超过了可用内存大小。
4.2 方法区的内部结构
1.类型信息:类、接口、枚举、方法的信息
2. 常量信息 加载时即被确认,存放于运行时常量池。
/**
* Project:TODO ADD PROJECT NAME
* Modify Information:
*/
package main.FirstDemo.jvm;
import java.io.Serializable;
/**
*/
public class MetaSpace2 extends Object implements Comparable<String>, Serializable {
public int num = 10;
private static String str = "测试字符串";
//空构造器
public void test1(){
int count = 20;
System.out.println("count="+count);
}
public static int test2(int cal){
int result = 0;
try{
int value = 30;
result = value/cal;
}catch (Exception w){
}
return result;
}
@Override
public int compareTo(String o) {
return 0;
}
}
//字节码文件
Classfile /D:/IdeaProjects/java-web/out/production/java-web/main/FirstDemo/jvm/Metaspace2.class
Last modified 2021-6-27; size 1512 bytes
MD5 checksum d8a1138b3900f740e6878fcc45f4c69b
Compiled from "MetaSpace2.java"
//类型信息
public class main.FirstDemo.jvm.MetaSpace2 extends java.lang.Object implements java.lang.Comparable, java.io.Serializable
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
//常量池
Constant pool:
#1 = Methodref #17.#49 // java/lang/Object."":()V
#2 = Fieldref #16.#50 // main/FirstDemo/jvm/MetaSpace2.num:I
#3 = Fieldref #51.#52 // java/lang/System.out:Ljava/io/PrintStream;
#4 = Class #53 // java/lang/StringBuilder
#5 = Methodref #4.#49 // java/lang/StringBuilder."":()V
#6 = String #54 // count=
#7 = Methodref #4.#55 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#8 = Methodref #4.#56 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#9 = Methodref #4.#57 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#10 = Methodref #58.#59 // java/io/PrintStream.println:(Ljava/lang/String;)V
#11 = Class #60 // java/lang/Exception
#12 = Class #61 // java/lang/String
#13 = Methodref #16.#62 // main/FirstDemo/jvm/MetaSpace2.compareTo:(Ljava/lang/String;)I
#14 = String #63 // 测试字符串
#15 = Fieldref #16.#64 // main/FirstDemo/jvm/MetaSpace2.str:Ljava/lang/String;
#16 = Class #65 // main/FirstDemo/jvm/MetaSpace2
#17 = Class #66 // java/lang/Object
#18 = Class #67 // java/lang/Comparable
#19 = Class #68 // java/io/Serializable
#20 = Utf8 num
#21 = Utf8 I
#22 = Utf8 str
#23 = Utf8 Ljava/lang/String;
#24 = Utf8
#25 = Utf8 ()V
#26 = Utf8 Code
#27 = Utf8 LineNumberTable
#28 = Utf8 LocalVariableTable
#29 = Utf8 this
#30 = Utf8 Lmain/FirstDemo/jvm/MetaSpace2;
#31 = Utf8 test1
#32 = Utf8 count
#33 = Utf8 test2
#34 = Utf8 (I)I
#35 = Utf8 value
#36 = Utf8 cal
#37 = Utf8 result
#38 = Utf8 StackMapTable
#39 = Class #60 // java/lang/Exception
#40 = Utf8 compareTo
#41 = Utf8 (Ljava/lang/String;)I
#42 = Utf8 o
#43 = Utf8 (Ljava/lang/Object;)I
#44 = Utf8
#45 = Utf8 Signature
#46 = Utf8 Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable;
#47 = Utf8 SourceFile
#48 = Utf8 MetaSpace2.java
#49 = NameAndType #24:#25 // "":()V
#50 = NameAndType #20:#21 // num:I
#51 = Class #69 // java/lang/System
#52 = NameAndType #70:#71 // out:Ljava/io/PrintStream;
#53 = Utf8 java/lang/StringBuilder
#54 = Utf8 count=
#55 = NameAndType #72:#73 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#56 = NameAndType #72:#74 // append:(I)Ljava/lang/StringBuilder;
#57 = NameAndType #75:#76 // toString:()Ljava/lang/String;
#58 = Class #77 // java/io/PrintStream
#59 = NameAndType #78:#79 // println:(Ljava/lang/String;)V
#60 = Utf8 java/lang/Exception
#61 = Utf8 java/lang/String
#62 = NameAndType #40:#41 // compareTo:(Ljava/lang/String;)I
#63 = Utf8 测试字符串
#64 = NameAndType #22:#23 // str:Ljava/lang/String;
#65 = Utf8 main/FirstDemo/jvm/MetaSpace2
#66 = Utf8 java/lang/Object
#67 = Utf8 java/lang/Comparable
#68 = Utf8 java/io/Serializable
#69 = Utf8 java/lang/System
#70 = Utf8 out
#71 = Utf8 Ljava/io/PrintStream;
#72 = Utf8 append
#73 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#74 = Utf8 (I)Ljava/lang/StringBuilder;
#75 = Utf8 toString
#76 = Utf8 ()Ljava/lang/String;
#77 = Utf8 java/io/PrintStream
#78 = Utf8 println
#79 = Utf8 (Ljava/lang/String;)V
{
//域信息
public int num;
descriptor: I
flags: ACC_PUBLIC
private static java.lang.String str;
descriptor: Ljava/lang/String;
flags: ACC_PRIVATE, ACC_STATIC
public main.FirstDemo.jvm.MetaSpace2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: aload_0
5: bipush 10
7: putfield #2 // Field num:I
10: return
LineNumberTable:
line 33: 0
line 35: 4
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lmain/FirstDemo/jvm/MetaSpace2;
//方法信息
public void test1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=1
0: bipush 20
2: istore_1
3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
6: new #4 // class java/lang/StringBuilder
9: dup
10: invokespecial #5 // Method java/lang/StringBuilder."":()V
13: ldc #6 // String count=
15: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
18: iload_1
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
22: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
25: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
LineNumberTable:
line 40: 0
line 41: 3
line 42: 28
LocalVariableTable:
Start Length Slot Name Signature
0 29 0 this Lmain/FirstDemo/jvm/MetaSpace2;
3 26 1 count I
public static int test2(int);
descriptor: (I)I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: bipush 30
4: istore_2
5: iload_2
6: iload_0
7: idiv
8: istore_1
9: goto 13
12: astore_2
13: iload_1
14: ireturn
//异常信息表 从2-9(字节码指令地址)能包裹住的代码
Exception table:
from to target type
2 9 12 Class java/lang/Exception
LineNumberTable:
line 45: 0
line 48: 2
line 49: 5
line 52: 9
line 50: 12
line 53: 13
LocalVariableTable:
Start Length Slot Name Signature
5 4 2 value I
0 15 0 cal I
2 13 1 result I
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 12
locals = [ int, int ]
stack = [ class java/lang/Exception ]
frame_type = 0 /* same */
public int compareTo(java.lang.String);
descriptor: (Ljava/lang/String;)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iconst_0
1: ireturn
LineNumberTable:
line 57: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this Lmain/FirstDemo/jvm/MetaSpace2;
0 2 1 o Ljava/lang/String;
public int compareTo(java.lang.Object);
descriptor: (Ljava/lang/Object;)I
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #12 // class java/lang/String
5: invokevirtual #13 // Method compareTo:(Ljava/lang/String;)I
8: ireturn
LineNumberTable:
line 33: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lmain/FirstDemo/jvm/MetaSpace2;
//方法
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #14 // String 测试字符串
2: putstatic #15 // Field str:Ljava/lang/String;
5: return
LineNumberTable:
line 36: 0
}
Signature: #46 // Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable;
SourceFile: "MetaSpace2.java"
========================================================
public static int count = 1; //准备阶段赋零值 初始化阶段赋真实值
public static final int number = 2; //编译的时候就赋真实值
4.3 运行时常量池
常量池
类和接口编译后会产生一个字节码文件,而字节码需要数据支持,通常这种数据会很大以至于不能支持存到字节码里。因此将这些数据存到常量池,字节码中包含了指向常量池的引用。
运行时常量池
运行时常量池是方法区的一部分,Jvm为每一个已加载的类和接口都会维护一个常量池。运行时常量池包含多种不同的常量,包括编译期已经确认的数值字面量,也包括到运行期解释后才能获得的方法或字段引用。注意此时不是常量池中的符号引用了,而是真实的引用地址。在Java语言中,并不要求常量只能在编译期间产生,运行期间一样也可以让新常量入池,像String类的intern()方法就能做到新常量入池的操作,这就是运行时常量池的动态性表现了。
4.4 方法区的演进
1.StringTable为什么会移到堆区?
因为jdk1.6中当字符串存储在永久代时,只有永久代空间满了 才会触发Full GC,导致字符串回收效率很低,放到堆里能及时回收内存。
2.静态变量
private static byte[] arr = new byte[1024*1024*100]
注意:byte数组具体的值一直是存放于堆中 arr的引用位置是随着jdk发生了变化。