Skip to content

Commit 0f35e8b

Browse files
committed
Update Java Notes
1 parent f6d4fb6 commit 0f35e8b

1 file changed

Lines changed: 47 additions & 26 deletions

File tree

JavaSE.md

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12581,16 +12581,22 @@ Java**反编译**指令:`javap -v Test.class`
1258112581

1258212582
#### 虚拟机栈
1258312583

12584-
Java 虚拟机栈:Java Virtual Machine Stacks每个线程运行时所需要的内存
12584+
Java 虚拟机栈:Java Virtual Machine Stacks**每个线程**运行时所需要的内存
1258512585

1258612586
* 虚拟机栈时线程私有的,对应方法调用到执行完成的整个过程
12587-
* 保存执行方法时的**局部变量、动态连接信息、方法返回地址信息**
12587+
12588+
* 保存执行方法时的**局部变量表、常量池引用、方法返回地址信息**
12589+
1258812590
* 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
12591+
1258912592
* 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
1259012593

12594+
<img src="https://gitee.com/seazean/images/raw/master/JavaSE/JVM-虚拟机栈.png" style="zoom:50%;" />
12595+
1259112596
设置栈内存大小:`-Xss size` `-Xss 1024k`
1259212597

1259312598
* 进入 Run/Debug Configurations ---> VM options 设置参数
12599+
*JDK 1.4 中默认为 256K,而在 JDK 1.5+ 默认为 1M
1259412600

1259512601
虚拟机栈特点:
1259612602

@@ -12602,10 +12608,10 @@ Java 虚拟机栈:Java Virtual Machine Stacks,每个线程运行时所需要
1260212608
* 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
1260312609
* 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全
1260412610

12605-
栈内存溢出
12611+
异常
1260612612

12607-
* 栈帧过多导致栈内存溢出 (超过了栈的容量)
12608-
* 栈帧过大导致栈内存溢出
12613+
* 栈帧过多导致栈内存溢出 (超过了栈的容量),会抛出 OutOfMemoryError 异常
12614+
* 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常
1260912615

1261012616
线程运行诊断:
1261112617

@@ -12624,7 +12630,9 @@ Java 虚拟机栈:Java Virtual Machine Stacks,每个线程运行时所需要
1262412630

1262512631
* 不需要进行GC,与虚拟机栈类似
1262612632

12627-
* 本地方法一般是由其他语言编写
12633+
* 本地方法一般是由其他语言编写,并且被编译为基于本机硬件和操作系统的程序,对这些方法需要特别处理
12634+
12635+
<img src="https://gitee.com/seazean/images/raw/master/JavaSE/JVM-本地方法栈.png" style="zoom:67%;" />
1262812636

1262912637

1263012638

@@ -12636,7 +12644,7 @@ Java 虚拟机栈:Java Virtual Machine Stacks,每个线程运行时所需要
1263612644

1263712645
Program Counter Register 程序计数器(寄存器)
1263812646

12639-
作用:内部保存字节码的行号,用于记录正在执行的字节码指令地址(下一条jvm指令的地址
12647+
作用:内部保存字节码的行号,用于记录正在执行的字节码指令地址(如果正在执行的是本地方法则为空
1264012648

1264112649
原理:
1264212650

@@ -12669,16 +12677,16 @@ Program Counter Register 程序计数器(寄存器)
1266912677

1267012678
#### 堆
1267112679

12672-
Heap 堆:主要用来保存**对象实例,数组**等,通过 new 关键字创建对象都会使用堆内存
12680+
Heap 堆:用来保存**对象实例,数组**等,通过 new 创建对象都会使用堆内存,是垃圾收集的主要区域("GC 堆")
12681+
1267312682
特点:
1267412683

1267512684
* 它是线程共享的,堆中对象都需要考虑线程安全的问题
1267612685
* 有垃圾回收机制
12677-
* 当堆中没有内存空间可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常
1267812686

1267912687
设置堆内存指令:`-Xmx Size`
1268012688

12681-
内存溢出:new出对象,循环添加字符数据
12689+
内存溢出:new出对象,循环添加字符数据,当堆中没有内存空间可分配给实例,也无法再扩展时,就会抛出OutOfMemoryError异常
1268212690

1268312691
堆内存诊断工具:(控制台命令)
1268412692

@@ -12704,13 +12712,30 @@ public static void main(String[] args) throws InterruptedException {
1270412712

1270512713
* Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区。Survivor区间,某一时刻只有其中一个是被使用的,另外一个留做垃圾回收时复制对象。在Eden区变满的时候, GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾回收后,仍然存活于Survivor的对象将被移动到Tenured区间
1270612714
* Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured
12707-
* Perm代主要保存**ClassClassLoader、静态变量、常量、编译后的代码**,在java7中堆内方法区会受到GC的管理。方法区(永久代)有大小的限制,如果大量的动态生成类,放入到方法区,很容易造成OOM
12715+
* Perm代主要保存**ClassClassLoader、静态变量、常量、编译后的代码**,在java7中堆内方法区会受到GC的管理。
12716+
12717+
12718+
12719+
***
12720+
12721+
12722+
12723+
#### 方法区
1270812724

12709-
Java8
12725+
方法区 / 永久代:在HotSpot JVM中,用于存放已被加载的类信息、常量池、静态变量以及即时编译器编译后的代码等数据,每当一个类初次被加载时,它的**元数据**都会放到永久代中
1271012726

12711-
* 为了**避免方法区出现OOM**,在java8中将堆内的方法区(永久代)移动到了本地内存上,重新开辟了一块空间,叫做**元空间**
12727+
方法区是一个 JVM 规范,**永久代与元空间都是其一种实现方式**
1271212728

12729+
方法区和堆一样不需要连续的内存,并且可以动态扩展;方法区有大小限制,因此加载的类太多,可能导致永久代内存溢出 (OutOfMemoryError);对这块区域进行垃圾回收主要是对常量池的回收和对类的卸载,比较难实现
1271312730

12731+
为了**避免方法区出现OOM**,在JDK8中将堆内的方法区(永久代)移动到了本地内存上,重新开辟了一块空间,叫做**元空间**,元空间存储类的元信息,静态变量和常量池等放入堆中
12732+
12733+
12734+
12735+
**运行时常量池**是方法区的一部分
12736+
12737+
* Class 文件中的常量池(编译器生成的字面量和符号引用)会在类加载后被放入这个区域
12738+
* 除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()
1271412739

1271512740

1271612741

@@ -12735,20 +12760,15 @@ Java8:
1273512760

1273612761

1273712762

12763+
***
1273812764

1273912765

12740-
##### 元空间
12741-
12742-
HotSpot JVM 中,永久代( ≈ 方法区)中用于存放类和方法的元数据以及常量池,每当一个类初次被加载的时候,它的元数据都会放到永久代中。永久代是有大小限制的,因此加载的类太多,很可能导致永久代内存溢出,即OutOfMemoryError
12743-
12744-
Java 8PermGen 被移出 HotSpot JVM
1274512766

12746-
* 由于 PermGen 内存经常会溢出,引发OutOfMemoryError,为了让这一块内存可以更灵活地被管理,不要经常出现OOM
12747-
* 移除 PermGen 可以促进 HotSpot JVMJRockit VM 的融合,因为 JRockit 没有永久代
12767+
##### 元空间
1274812768

12749-
PermGen 被元空间代替,其他内容比如**类元信息、字段、静态属性、方法、常量池**等都移动到元空间区,元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现
12769+
PermGen 被元空间代替,其他内容比如**类信息、字段、静态属性、方法、常量池**等都移动到元空间区,元空间的本质和永久代类似,都是对 JVM 规范中方法区的实现
1275012770

12751-
元空间与永久代区别:元空间并不在虚拟机中,而是使用本地内存。因此默认情况下,元空间的大小仅受本地内存限制
12771+
元空间与永久代区别:元空间不在虚拟机中,使用的本地内存,默认情况下,元空间的大小仅受本地内存限制
1275212772

1275312773
方法区内存溢出:
1275412774

@@ -12795,7 +12815,7 @@ public class Demo1_8 extends ClassLoader { // 可以用来加载类的二进制
1279512815

1279612816

1279712817

12798-
12818+
***
1279912819

1280012820

1280112821

@@ -12810,9 +12830,9 @@ Direct Memory特点:
1281012830
分配和回收原理:
1281112831

1281212832
* 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法
12813-
* ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦
12814-
* ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调
12815-
用 freeMemory 来释放直接内存
12833+
* ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存
12834+
12835+
<img src="https://gitee.com/seazean/images/raw/master/JavaSE/JVM-直接内存.png" style="zoom:50%;" />
1281612836

1281712837
```java
1281812838
/**
@@ -12867,6 +12887,7 @@ public class Demo1_27 {
1286712887
| -XX:+PrintFlagsFinal | 查看所有的参数的最终值<br />(可能会存在修改,不再是初始值) |
1286812888
| -XX:+PrintGCDetails | GC详情,打印gc简要信息:<br />1. -XX+PrintGC 2. - verbose:gc |
1286912889
| -XX:+ScavengeBeforeFullGC | FullGCMinorGC |
12890+
| -XX:+DisableExplicitGC | 禁用显式垃圾回收,让System.gc无效 |
1287012891

1287112892

1287212893

0 commit comments

Comments
 (0)