一、概述

1、介绍

  《Java虚拟机规范》中明确说明:尽管所有的方法区在逻辑上属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。但对于HotSpot JVM而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。
  所以,方法区看作是一块独立于Java堆的内存空间。官方文档:

  方法区在JVM启动的时候被创建,并且它的实际的物理内存空间和Java堆区一样,可以是不连续的。方法区的大小和堆一样,可选择固定大小或可扩展。方法区的大小决定了系统可以保持多少个类,如果系统定义了太多的类,导致方法区溢出,会报OOM。比如:加载大量的第三方jar包,Tomcat部署的工程过多(30~50个),大量动态的生成反射类。关闭JVM,会释放这个区域的内存。

2、栈、堆、方法区的交互关系

3、方法区的演进

  把方法区理解成接口,永久代和元空间是这个接口的落地实现。在JDK7及以前,习惯上把方法区称为永久代,JDK8开始,使用元空间取代了永久代。二者最大的区别是:元空间不在虚拟机设置的内存中,而是使用本地内存。
  本质上,方法区和永久代并不等价,仅是对HotSpot而言的。《Java虚拟机规范》对如何实现方法区,不做统一要求,像BEA JRockit,IBM J9中不存在永久代。
  如果方法区无法满足新的内存分配需求时,将报OOM。现在来看,当年使用永久代,不是好的idea,导致Java程序更容易OOM(超过-XX:MaxPermSize上限)。

4、设置方法区大小与OOM

  方法区的大小不是固定的,可以动态调整。
  JDK7及以前:
  -XX:PerSize来设置永久代初始空间大小。默认值是20.75M
  -XX:MaxPerSize来设置永久代最大空间大小。32位机器默认是64M,64位机器默认是82M。
  当JVM加载的类信息容量超过这个值,会报OOM:PerGen space
  JDK8及以后:
  元空间的大小可以使用-XX:MetaspaceSize和-XX:MaxMetaspaceSize指定。
  Windows下,-XX:MetaspaceSize=约21M,-XX:MaxMetaspaceSize=-1,即没有限制。默认值依赖平台。对于一个64位的服务器端JVM来说,默认-XX:MetaspaceSize=21M。一旦触及这个水位线,Full GC将会触发,并卸载没用的类(即这些类对应的类加载器不再存活)。然后这个水位线将会重置,新的水位线的值取决于GC后释放了多少元空间。如果释放的空间不足,那么在不超过MaxMetaspaceSize时,适当提高该值。如果释放空间过多,则适当降低该值。
  如果初始的水位线设置过低,上述水位线调整情况会发生很多次。通过垃圾回收器的日志可以观察到Full GC多次调用。为了避免频繁FC,建议将初始值设置为一个相对较高的值。
  代码示例:方法区OOM

 1 // jdk6/7中:
2 // -XX:PermSize=10m -XX:MaxPermSize=10m
3
4 // jdk8中:
5 // -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
6 public class OOMTest extends ClassLoader {
7 public static void main(String[] args) {
8 int j = 0;
9 try {
10 OOMTest test = new OOMTest();
11 for (int i = 0; i < 10_000; i++) {
12 // 创建ClassWriter对象,用于生成类的二进制字节码
13 ClassWriter classWriter = new ClassWriter(0);
14 // 指明版本号,修饰符,类名,包名,父类,接口
15 classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);
16
17 byte[] code = classWriter.toByteArray();
18
19 // 类的加载
20 // Class对象
21 test.defineClass("Class" + i, code, 0, code.length);
22
23 j++;
24 }
25 } finally {
26 System.out.println(j);
27 }
28 }
29 }
30
31 // 不设置参数
32 // 10000.无报错.使用动态的方法区,元空间.
33 // 在元空间创建并加载了10000个类.元空间做了一个动态的扩展.
34
35 // JDK8设置参数
36 // 8466.
37 // Exception in thread "main" java.lang.OutOfMemoryError: Metaspace

  如何解决这些OOM?
  (1)要解决OOM异常或heap space的异常,一般的手段是首先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。
  (2)如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots到引用链。于是就能找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息,以及GC Roots引用链的信息,就可以比较准确的定位出泄漏代码的位置。
  (3)如果不存在内存泄漏,内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx,-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长,持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

二、方法区的内部结构

1、介绍

  《深入理解Java虚拟机》书中对方法区存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编辑器编译后的代码缓存等。

  注意:这里只是一个经典的结构图,不完全正确。因为在jdk7以后,静态变量,运行时常量池里面的字符串常量池有变化,不再放在方法区了,而是放在了堆空间,这个后面会提到(看图)。

2、类型信息

  对每个加载的类型(类Class、接口Interface、枚举Enum、注解Annotation),JVM必须在方法区中存储以下类型信息:
  (1)这个类型的完整类路径(包名.类名)。
  (2)这个类型直接父类的完整类路径。
  (3)这个类型的修饰符(public,abstract,final的某个子集)。
  (4)这个类型直接接口的一个有序列表。
  类型信息里记录了,这个类是使用哪个类加载器加载进来的。

3、域(Field)信息

  JVM必须在方法区中保存类型的所有域的相关信息以及域的声明顺序。域的相关信息包括:域名称、域类型、域修饰符(public、private、protected、static、final、volatile、transient的某个子集)。

4、方法信息

  JVM必须保存所有方法以下信息,同域信息一样包括声明顺序:
  (1)方法名称。
  (2)方法的返回类型(或void)。
  (3)方法的参数列表。
  (4)方法的修饰符(public、private、protected、static、final、synchronized、native、abstract的某个子集)。
  (5)方法的字节码、操作数栈、局部变量表及大小(abstract和native方法除外)。
  (6)异常表(abstract和native方法除外),每个异常处理的开始位置,结束位置,代码处理在程序计数器中的偏移地址,被捕获的异常类的常量池索引。
  代码示例:方法区的内部构成

 1 public class Main extends Object implements Comparable<String>, Serializable {
2 //属性
3 public int num = 10;
4 private static String str = "测试方法的内部结构";
5
6 public void test1() {
7 int count = 20;
8 System.out.println("count = " + count);
9 }
10
11 public static int test2(int cal) {
12 int result = 0;
13 try {
14 int value = 30;
15 result = value / cal;
16 } catch (Exception e) {
17 e.printStackTrace();
18 }
19 return result;
20 }
21
22 @Override
23 public int compareTo(String o) {
24 return 0;
25 }
26 }

  1 javap -v -p Main.class > temp.txt
2
3 // 解析后的字节码文件.(删掉了部分无关的信息)
4 Classfile /D:/workspace/Java/myweb/target/classes/com/lx/myweb/Main.class
5 Last modified 2020-10-6; size 1670 bytes
6 MD5 checksum 54aed047bf420df2ddb06256a1ed4a33
7 Compiled from "Main.java"
8
9 // 类型信息
10 public class com.lx.myweb.Main extends java.lang.Object implements java.lang.Comparable<java.lang.String>, java.io.Serializable
11 minor version: 0
12 major version: 52
13 flags: ACC_PUBLIC, ACC_SUPER
14
15 // 常量池.#1:符号引用
16 Constant pool:
17 #1 = Methodref #18.#53 // java/lang/Object."<init>":()V
18 ……
19 #85 = Utf8 printStackTrace
20 {
21
22 // 域信息
23 public int num;
24 descriptor: I
25 flags: ACC_PUBLIC
26
27 private static java.lang.String str;
28 descriptor: Ljava/lang/String;
29 flags: ACC_PRIVATE, ACC_STATIC
30
31 // 方法信息(构造器)
32 public com.lx.myweb.Main();
33 descriptor: ()V
34 flags: ACC_PUBLIC
35 Code:
36 stack=2, locals=1, args_size=1
37 0: aload_0
38 1: invokespecial #1 // Method java/lang/Object."<init>":()V
39 4: aload_0
40 5: bipush 10
41 7: putfield #2 // Field num:I
42 10: return
43 LineNumberTable:
44 line 6: 0
45 line 8: 4
46 LocalVariableTable:
47 Start Length Slot Name Signature
48 0 11 0 this Lcom/lx/myweb/Main;
49
50 // 方法信息
51 public void test1();
52 descriptor: ()V
53 flags: ACC_PUBLIC
54 Code:
55 stack=3, locals=2, args_size=1
56 0: bipush 20
57 2: istore_1
58 3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
59 6: new #4 // class java/lang/StringBuilder
60 9: dup
61 10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
62 13: ldc #6 // String count =
63 15: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
64 18: iload_1
65 19: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
66 22: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
67 25: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
68 28: return
69 LineNumberTable:
70 line 12: 0
71 line 13: 3
72 line 14: 28
73 LocalVariableTable:
74 Start Length Slot Name Signature
75 0 29 0 this Lcom/lx/myweb/Main;
76 3 26 1 count I
77
78 // 方法信息
79 public static int test2(int);
80 descriptor: (I)I
81 flags: ACC_PUBLIC, ACC_STATIC
82 Code:
83 stack=2, locals=3, args_size=1
84 0: iconst_0
85 1: istore_1
86 2: bipush 30
87 4: istore_2
88 5: iload_2
89 6: iload_0
90 7: idiv
91 8: istore_1
92 9: goto 17
93 12: astore_2
94 13: aload_2
95 14: invokevirtual #12 // Method java/lang/Exception.printStackTrace:()V
96 17: iload_1
97 18: ireturn
98 Exception table:
99 from to target type
100 2 9 12 Class java/lang/Exception
101 LineNumberTable:
102 line 17: 0
103 line 19: 2
104 line 20: 5
105 line 23: 9
106 line 21: 12
107 line 22: 13
108 line 24: 17
109 LocalVariableTable:
110 Start Length Slot Name Signature
111 5 4 2 value I
112 13 4 2 e Ljava/lang/Exception;
113 0 19 0 cal I
114 2 17 1 result I
115 StackMapTable: number_of_entries = 2
116 frame_type = 255 /* full_frame */
117 offset_delta = 12
118 locals = [ int, int ]
119 stack = [ class java/lang/Exception ]
120 frame_type = 4 /* same */
121 MethodParameters:
122 Name Flags
123 cal
124
125 // 子类方法信息
126 public int compareTo(java.lang.String);
127 descriptor: (Ljava/lang/String;)I
128 flags: ACC_PUBLIC
129 Code:
130 stack=1, locals=2, args_size=2
131 0: iconst_0
132 1: ireturn
133 LineNumberTable:
134 line 29: 0
135 LocalVariableTable:
136 Start Length Slot Name Signature
137 0 2 0 this Lcom/lx/myweb/Main;
138 0 2 1 o Ljava/lang/String;
139 MethodParameters:
140 Name Flags
141 o
142
143 // 父类方法信息
144 public int compareTo(java.lang.Object);
145 descriptor: (Ljava/lang/Object;)I
146 flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
147 Code:
148 stack=2, locals=2, args_size=2
149 0: aload_0
150 1: aload_1
151 2: checkcast #13 // class java/lang/String
152 5: invokevirtual #14 // Method compareTo:(Ljava/lang/String;)I
153 8: ireturn
154 LineNumberTable:
155 line 6: 0
156 LocalVariableTable:
157 Start Length Slot Name Signature
158 0 9 0 this Lcom/lx/myweb/Main;
159 MethodParameters:
160 Name Flags
161 o synthetic
162
163 // 静态变量信息
164 static {};
165 descriptor: ()V
166 flags: ACC_STATIC
167 Code:
168 stack=1, locals=0, args_size=0
169 0: ldc #15 // String 测试方法的内部结构
170 2: putstatic #16 // Field str:Ljava/lang/String;
171 5: return
172 LineNumberTable:
173 line 9: 0
174 }
175 Signature: #50 // Ljava/lang/Object;Ljava/lang/Comparable<Ljava/lang/String;>;Ljava/io/Serializable;
176 SourceFile: "Main.java"

字节码文件

5、non-final的类变量

  静态变量和类关联在一起,随着类的加载而加载,它们成为类数据在逻辑上的一部分。类变量被类的所有实例共享,即使没有类实例,也可访问。
  代码示例:

 1 public class Main {
2 public static void main(String[] args) {
3 Order order = null;
4 order.method();
5
6 System.out.println(order.count);
7 }
8 }
9
10 class Order {
11 public static int count = 1;
12
13 public static void method() {
14 System.out.println("count = " + count);
15 }
16 }
17
18 // IDEA会提示有编译错误.但是直接执行不会报错,不会有空指针.
19 // count = 1
20 // 1

6、final的类变量:全局常量

  被声明为 final static 的变量的处理方法不同,每个全局常量在编译的时候就被分配了。
  代码示例:

1 public class Main {
2
3 public static int count = 1;
4 public static final int num = 100;
5
6 public static void method() {
7 System.out.println("count = " + count);
8 }
9 }
 1 javap -v -p Main.class > temp.txt
2
3 // 解析后的字节码文件.(删掉了部分无关的信息)
4 {
5 public static int count;
6 descriptor: I
7 flags: ACC_PUBLIC, ACC_STATIC
8
9 public static final int num;
10 descriptor: I
11 flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
12 ConstantValue: int 100 // 声明为final的静态变量在编译时就有值了
13 }

7、常量池

  方法区,内部包含了运行时常量池;字节码文件,内部包含了常量池。要理解方法区,就需要理解清楚字节码文件,因为加载类的信息都在方法区。要理解方法区的运行时常量池,就需要理解字节码文件的常量池。

  一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述信息外,还包含一项信息,就是常量池(constant pool),包括各种字面量和对类型、域、方法的符号引用。
  (1)为什么需要常量池?
  一个Java源文件中的类、接口,编译后产生一个字节码文件。而Java中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里。换一种方式,可以存到常量池,这个字节码包含了指向常量池的引用。在动态链接的时候会用到运行时常量池。
  代码示例:

1 public class Main {
2 public static void main(String[] args) {
3 System.out.println("hello world");
4 }
5 }

  这里面使用了String、System、PrintStream及Object等结构。这里代码量已经很小了,如果代码多,引用到的结构会更多,就需要常量池了!
  (2)常量池中有什么?
  常量池内存储的数据类型包括:数量值,字符串值,类引用,字段引用,方法引用。

  小结:常量池,可以看做一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型。

8、运行时常量池

  运行时常量池是方法区的一部分。
  常量池表(Constant Pool)是Class文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
  JVM为每个已加载的类型(类或接口)都维护一个常量池,池中的数据项像数组项一样,是通过索引访问的。
  运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或字段引用,此时不再是常量池中的符号地址了,这里换为真实地址。
  运行时常量池,相对于Class文件常量池的另一重要特征是,具备动态性。
  运行时常量池类似于传统编程语言中的符号表,但是它所包含的数据却比符号表要更加丰富一些。
  字节码文件中的常量池经过类加载器加载放到方法区以后,对应的结构就称为运行时常量池。

三、方法区的使用举例

  代码示例:方法区使用举例

1 public class Main {
2 public static void main(String[] args) {
3 int x = 500;
4 int y = 100;
5 int a = x / y;
6 int b = 50;
7 System.out.println(a + b);
8 }
9 }

  下面讲解在程序执行的过程中,main方法的指令在一个一个执行的过程当中,程序计数器,虚拟机栈之间的协作关系。由于没有new对象,就不看堆空间的情况了。

四、方法区的演进细节(重要)

1、介绍

  首先明确,只有HotSpot才有永久代,BEA JRockit,IBM J9中不存在永久代。方法区如何实现属于虚拟机实现细节,《Java虚拟机规范》并不要求统一。
  JDK6及以前、JDK7、JDK8及以后,方法区的变化:

  StringTable,字符串常量池。
  注意:JDK7,此时的方法区(永久代)还是用的虚拟机的内存,和本地内存还有一个映射的概念。JDK8用的本地内存,不再使用虚拟机的内存。

2、永久代为什么被元空间替换?

  官网给的理由是因为 JRockit 没有,为了整合JRockit和Hotspot,所以去掉了。这里也很明确的可以看到,将字符串常量池与静态变量移动到堆中。

  http://openjdk.java.net/jeps/122

  随着Java8 的到来,HotSpot VM中再也见不到永久代了。但这并不意味着类的元数据信息消失了,这些数据被移到了一个与堆不相连的本地内存区域,这个区域叫元空间。
  由于类的元数据分配在本地内存中,元空间的最大可分配空间就是系统可用内存空间。这项变动是很有必要的,原因:
  (1)为永久代设置空间大小是很难确定的。在某些场景下,如果动态加载类过多,容易产生Perm区的OOM。比如某个实际Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误。而元空间和永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。
  (2)对永久代进行调优是很困难的。对永久代的 Full GC 需要去判断这个类或者这个常量,不再被使用了,也挺花时间的。所以调优也会变得很困难。

3、StringTable(字符串常量池)为什么要调整位置?

  因为永久代的回收效率很低,在Full GC的时候才会触发。而Full GC是老年代的空间不足、永久代不足时才会触发,这就导致StringTable回收效率不高。而开发中会有大量的字符串被创建,回收效率低,将导致永久代内存不足,放到堆里,能及时回收内存。

4、如何证明静态变量存在哪?

  代码示例:

 1 // jdk7:-Xms200m -Xmx200m -XX:PermSize=300m -XX:MaxPermSize=300m -XX:+PrintGCDetails
2 // jdk8:-Xms200m -Xmx200m -XX:MetaspaceSize=300m -XX:MaxMetaspaceSize=300m -XX:+PrintGCDetails
3 public class Main {
4 // 100MB
5 private static byte[] arr = new byte[1024 * 1024 * 100];
6
7 public static void main(String[] args) {
8 System.out.println(Main.arr);
9
10 // try {
11 // Thread.sleep(1000_000);
12 // } catch (InterruptedException e) {
13 // e.printStackTrace();
14 // }
15 }
16 }

  结果:基于jdk8。jdk6,jdk7没有演示。

  结论:jdk6,7,8,静态引用对应的对象实体始终都存在堆空间。
  注意:这里指的new的对象实体,始终都在堆空间中。上面(图示)指的变化,是静态变量 arr 这个变量名。
  那么如何验证呢?
  案例:一个静态属性,一个非静态属性,一个局部变量。这三个变量的对象放在哪? 这三个变量本身放在哪?这是《深入理解Java虚拟机》中的案例,staticObj、instanceObj、localObj存放在哪里?
  代码示例:

 1 // staticObj、instanceObj、localObj存放在哪里?
2 public class StaticObjTest {
3
4 static class Test {
5 static ObjectHolder staticObj = new ObjectHolder();
6 ObjectHolder instanceObj = new ObjectHolder();
7
8 void foo() {
9 ObjectHolder localObj = new ObjectHolder();
10 System.out.println("done");
11 }
12 }
13
14 private static class ObjectHolder {
15 }
16
17 public static void main(String[] args) {
18 Test test = new StaticObjTest.Test();
19 test.foo();
20 }
21 }

  这里需要使用一个工具,JHSDB,这个工具JDK9才有。结论:

  这三个地址都在eden区,也就是在堆中。也就证明了这三个对象实体都在堆中。即:只要是new出来的对象实体都在堆中。

五、方法区的垃圾回收

1、介绍

  《Java虚拟机规范》对方法区的约束是非常宽松的,提到过可以不要求虚拟机在方法区中实现垃圾收集。事实上,也确实有未实现或未能完整实现方法区类型卸载的收集器存在,如JDK 11时期的ZGC收集器就不支持类卸载。
  一般来说,这个区域的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻。但是这部分区域的回收有时又确实是必要的。以前Sun公司的Bug列表中,曾出现过的若干个严重的Bug就是由于低版本的HotSpot虚拟机对此区域未完全回收而导致内存泄漏。
  方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。

2、回收内容

  方法区常量池中主要存放的两大类常量:字面量和符号引用。
  字面量比较接近Java语言层次的常量概念,如文本字符串、被声明为final的常量值等。
  符号引用则属于编译原理方面的概念,包括下面三类常量:
  (1)类和接口的全限定名
  (2)字段的名称和描述符
  (3)方法的名称和描述符
  HotSpot虚拟机对常量池的回收策略是很明确的,只要常量池中的常量没有被任何地方引用,就可以被回收。回收废弃常量与回收Java堆中的对象非常类似。

3、判定需要回收

4、小结

  方法区要不要垃圾回收?Java虚拟机规范中没有明说,可以回收,也可以不回收。平时说的HotSpot是要的。
  回收的话,主要针对的是什么?不再使用的类型信息,运行时常量池中废弃的常量。

  动态链接,指向了运行时常量池当前方法的引用。

JVM详解(五)——运行时数据区-方法区的更多相关文章

  1. JVM详解之:运行时常量池

    目录 简介 class文件中的常量池 运行时常量池 静态常量详解 String常量 数字常量 符号引用详解 String Pool字符串常量池 总结 简介 JVM在运行的时候会对class文件进行加载 ...

  2. JVM 专题十:运行时数据区(五)堆

    1. 核心概述 1.1 堆概述 一个进程对应一个jvm实例,一个运行时数据区,又包含多个线程,这些线程共享了方法区和堆,每个线程包含了程序计数器.本地方法栈和虚拟机栈. 一个jvm实例只存在一个堆内存 ...

  3. 【JVM第三篇--运行时数据区】程序计数器、虚拟机栈、本地方法栈

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.运行时数据区 我们在编写Java程序时,使用JVM的流程主要如下所示: 虚拟机在 ...

  4. Mysql常用show命令,show variables like xxx 详解,mysql运行时参数

    MySQL中有很多的基本命令,show命令也是其中之一,在很多使用者中对show命令的使用还容易产生混淆,本文汇集了show命令的众多用法. 详细: http://dev.mysql.com/doc/ ...

  5. JVM——内存区域:运行时数据区域详解

    关注微信公众号:CodingTechWork,一起学习进步. 引言   我们经常会被问到一个问题是Java和C++有何区别?我们除了能回答一个是面向对象.一个是面向过程编程以外,我们还会从底层内存管理 ...

  6. JVM系列之四:运行时数据区

    1. JVM架构图 Java虚拟机主要分为五大模块:类装载器子系统.运行时数据区.执行引擎.本地方法接口和垃圾收集模块. 2. JDK1.7内存模型-运行时数据区域 根据<Java 虚拟机规范( ...

  7. 【JVM第四篇--运行时数据区】堆

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.堆的概述 JVM的运行时数据区如下: 一个Java程序运行起来对应着一个进程(操 ...

  8. Jvm基础(1)-Java运行时数据区

    最近在看<深入理解Java虚拟机>,里面讲到了Java运行时数据区,这是Jvm基本知识,把读书笔记记录在此.这些知识属于常识,都能查到的,如果我有理解不对的地方,还请指出. 首先把图贴上来 ...

  9. JVM内存区域(运行时数据区)划分

    前言: 我们每天都在编写Java代码,编译,执行.很多人已经知道Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文 ...

  10. JVM 专题十三:运行时数据区(八)直接内存

    1. 直接内存 不是虚拟机运行时数据区的一部分,也不是<Java虚拟机规范>中定义的内存区域. 直接内存是Java堆外的.直接向系统申请的内存区间. 来源于NIO,通过存在堆中的Direc ...

随机推荐

  1. Heartbeat MySQL双主复制

    目录 一 基础环境 二 实际部署 2.1 安装MySQL 2.2 初始化MySQL 2.3 master01 my.cf配置 2.4 创建账号 2.5 master02 my.cf配置配置 2.6 创 ...

  2. kratos

    技术文章 日志库的使用姿势 通过 layout 探索 kratos 运行原理 发版日志 发布日志 - kratos v2.0.5 版本发布 发布日志 - kratos v2.0.4 版本发布

  3. multipass指定virualbox搭建k8s集群(选择docker作为默认容器)

    目录 前言 步骤 初始化三台虚拟机 统一安装docker 修改docker镜像源 查看masterIP 安装master节点(重点设置) 查看master的token 安装worker节点 测试 部署 ...

  4. Django的form组件——正则校验

    from django.contrib import admin from django.urls import path from app01 import views urlpatterns = ...

  5. openswan中的in_struct和out_struct函数

    openswan中的in_struct和out_struct函数 文章目录 openswan中的in_struct和out_struct函数 1. 花絮 2. in_struct代码实现分析 3. 它 ...

  6. Servlet生命周期和方法

    一.五个生命周期方法,有三个很重要,初始化方法.提供服务方法和销毁方法 1.三个主要方法 2.另外两个重写的成员方法只做了解 二.生命周期详解 其中,每次刷新页面都是一次对servlet访问: 页面访 ...

  7. JAVA安全基础之代理模式(一)

    JAVA安全基础之代理模式(一) 代理模式是java的一种很常用的设计模式,理解代理模式,在我们进行java代码审计时候是非常有帮助的. 静态代理 代理,或者称为 Proxy ,简单理解就是事情我不用 ...

  8. mysql忘记root密码连接本地库

    http://www.cnblogs.com/zf2011/archive/2012/03/13/2393387.html 今天想做个小项目,决定用mysql数据库,但是好久没用mysql了,也忘掉了 ...

  9. VS Code + WSL 搭建 RaspberryPi Pico 开发环境

    前面老周写一堆 .NET 与树莓派相关的水文.其实使用的是.net的 IOT 库,并不只是树莓派,其他运行 Linux 的开发板都适用,只要有 GPIO 就行.老周好像在哪看到过,有 USB 转GPI ...

  10. PTA——c++类与对象

    对于给定的一个字符串,统计其中数字字符出现的次数. 类和函数接口定义: 设计一个类Solution,其中包含一个成员函数count_digits,其功能是统计传入的string类型参数中数字字符的个数 ...