文章目录
栈、堆、方法区的交互关系
从线程共享与否的角度来看
方法区的理解
方法区在哪里?
方法区的基本理解
HotSpot中方法区的演进
方法区概述
设置方法区大小与OOM
-
方法区的大小不必是固定的,JVM可以根据应用的需要动态调整
-
JDK7及以前
- JDK8及以后
如何解决这些OOM?
方法区的内部结构
示意图
方法区(Method Area)存储什么?
类型信息
域(Field)信息
方法(Method)信息
non-final的类变量
-
静态变量和类关联在一起,随着类的加载而加载,他们成为类数据在逻辑上的一部分
-
类变量被类的所有实例共享,即使没有类实例时也可以访问它
/** * non-final的类变量 */ public class MethodAreaTest { public static void main(String[] args) { Order order = null; order.hello(); System.out.println(order.count); } } class Order { public static int count = 1; public static final int number = 2; public static void hello() { System.out.println("hello!"); } }
全局常量:static final
被声明为final的类型变量的处理方法则不同,每个全局常量在编译的时候就会被分配
运行时常量池VS常量池
为什么需要常量池?
常量池中有什么?
小结
常量池,可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型
运行时常量池
方法区使用举例
public class MethodAreaDemo {
public static void main(String[] args) {
int x = 500;
int y = 100;
int a = x / y;
int b = 50;
System.out.println(a + b);
}
}
Code:
stack=3, locals=5, args_size=1
0: sipush 500
3: istore_1
4: bipush 100
6: istore_2
7: iload_1
8: iload_2
9: idiv
10: istore_3
11: bipush 50
13: istore 4
15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
18: iload_3
19: iload 4
21: iadd
22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
25: return
方法区的演进细节
永久代为什么要被元空间替换?
StringTable为什么要调整?
静态变量放在哪里
/**
* 结论:
* 静态引用对应的对象实体始终都存在堆空间
*
* jdk7:
* -Xms200m -Xmx200m -XX:PermSize=300m -XX:MaxPermSize=300m -XX:+PrintGCDetails
* jdk 8:
* -Xms200m -Xmx200m -XX:MetaspaceSize=300m -XX:MaxMetaspaceSize=300m -XX:+PrintGCDetails
*/
public class StaticFieldTest {
private static byte[] arr = new byte[1024 * 1024 * 100];//100MB
public static void main(String[] args) {
System.out.println(StaticFieldTest.arr);
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 《深入理解Java虚拟机》中的案例:
* staticObj、instanceObj、localObj存放在哪里?
*/
public class StaticObjTest {
static class Test {
static ObjectHolder staticObj = new ObjectHolder();
ObjectHolder instanceObj = new ObjectHolder();
void foo() {
ObjectHolder localObj = new ObjectHolder();
System.out.println("done");
}
}
private static class ObjectHolder {
}
public static void main(String[] args) {
Test test = new StaticObjTest.Test();
test.foo();
}
}
方法区的垃圾回收