Skip to content

Commit

Permalink
chore(java/se): re-struct jvm note
Browse files Browse the repository at this point in the history
  • Loading branch information
Alice52 committed Aug 30, 2023
1 parent e01836e commit befbe8d
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 117 deletions.
2 changes: 1 addition & 1 deletion database
8 changes: 7 additions & 1 deletion dist/gateway/01.kong.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@
5. consumer
6. plugin

## plgins 开发
## plugins 开发

## practice

1. oneid plugin with aacs

---

## reference

1. https://zhuanlan.zhihu.com/p/577842078
2 changes: 2 additions & 0 deletions java/se/jvm/01.raw-question.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[toc]

## 1.SPI

## 2.ClassLoader 过程
Expand Down
97 changes: 16 additions & 81 deletions java/se/jvm/JVM.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@

- 栈是运行时的单位, 堆是存储时的单位

```java
Class Files ==> 类装载器子系统 Class loader
|| ||
---------------------------------------------------------------
| 运行时数据区[Runtime Data Area] |
| 方法区[share] JavaNoGC 本地方法栈 |
| Method Area Java Stack Native Method Stack |
| 永久区是对其的实现 |
| |
| 堆[share] 程序计数器 |
| Heap Program Counter Register |
|------------------------------------------------------------|
|| || || ||
执行引擎 ==> 本地方法接口 <== 本地方法库
Execution Engine <== Native Interface
```
```java
Class Files ==> 类装载器子系统 Class loader
|| ||
---------------------------------------------------------------
| 运行时数据区[Runtime Data Area] |
| 方法区[share] JavaNoGC 本地方法栈 |
| Method Area Java Stack Native Method Stack |
| 永久区是对其的实现 |
| |
| 堆[share] 程序计数器 |
| Heap Program Counter Register |
|------------------------------------------------------------|
|| || || ||
执行引擎 ==> 本地方法接口 <== 本地方法库
Execution Engine <== Native Interface
```

2. [ClassLoader](./ClassLoader.md)

Expand All @@ -36,71 +36,6 @@
2. 内存使用少
3. native 方法的 PC Registernull

### Method Area: PermGen space / Meta space

![avatar](/static/image/java/javase-jvm-jdk8-metadata.png)
![avatar](/static/image/java/javase-jvm-jdk7-metadata.png)

1. 非堆内存[元空间]和永久代通过使用 方法区 实现
2. jdk8 移除永久代的原因

- 因为永久代使用的是虚拟机的内存, 为永久代设置空间大小是很难确定的; 元空间直接使用物理内存且可以子调整[在 max 范围内]
- 对永久代进行调优是很困难的
- 更容易导致 Java 程序更容易 OOM, 永久代仍然使用的是 Java 虚拟机的内存
- 为融合 HotSpot JVM 与 JRockit VM 而做出的努力,因为 JRockit 没有永久代, 不需要配置永久代
- 可以在 GC 不进行暂停的情况下并发地释放类数据

3. 方法区的大小决定了系统可以加载多少个类:

- 如果系统定义的类太多可能会产生 OOM
- 关闭 JVM 就会释放方法区的内存

4. 特性

- 方法区(Method Area)同堆区一样, 是各个**线程共享**的内存区域
- 方法区内存可以是不连续的: 永久代逻辑和物理上都属于 heap
- 方法区的大小和堆空间一样可以动态调整[`元空间-XX:MaxMetaspaceSize=-1 无限制`]或者固定[永久代]

5. [存放内容](https://blog.csdn.net/Xu_JL1997/article/details/89433916): 类的元数据, 但是 Class 对象是存放在 heap 中的

- 运行时常量池
1. [常量池表]运行时常量池[引用]: **但是字符串常量池[1 个]在 heap 中, 字符串常量池本质是一个 hash 的 StringTable, value 还是引用**
2. JIt 的缓冲
- 类信息

1. 类型信息[存在于 Class 对象中]: 对每个加载的类型[Class/interface/enum/annotation], JM 必须在方法区中存储以下类型信息
- 全类名: 包名.类名
- 直接父类的全类名: interface/java.lang.Object 没有父类
- 类型的修饰符: public, abstract, final
- 类型直接接口的一个有序列表
2. 域信息: 类的属性/成员变量, 静态属性的值在 heap 中
- 类所有的成员变量相关信息[赋值语句]及声明顺序
- 域名称/域类型/域修饰符[pυblic/private/protected/static/final/volatile/transient]
3. 方法信息: 所有方法信息[包含构造方法], 声明顺序
- 方法名称
- 返回类型或 void
- 方法参数的数量和类型[按顺序]
- 修饰符: [public/private/protected/static/final/synchronized/native/abstract]
- 方法的内容字节码 bytecodes + 操作数栈 + 局部变量表及大小[abstract 和 native 方法除外]
- 异常表[abstract 和 native 方法除外]:每个异常处理的开始位置, 结束位置, 代码处理在程序计数器中的偏移地址, 被捕获的异常类的常量池索引
4. 类初始化代码: 静态初始化代码块 + 动态代码块
5. 方法的符号引用

6. 方法区的 GC 问题

- 在 Java7 及之前, HotSpot 虚拟机中将 GC 分代收集扩展到了方法区, 主要是针对常量池的回收和对类型的卸载
- 而在 Java8 中, 已经彻底没有了永久代, 通过一个存储于堆内的 DirectByteBuffer 对象作为对元空间引用的操作
1. 分配空间时: 虚拟机维护了一个阈值默认 windows-21M, 如果 Metaspace 的空间大小超过了这个阈值, 那么在新的空间分配申请时, 虚拟机首先会通过收集可以卸载的类加载器来达到复用空间的目的, 而不是扩大 Metaspace 的空间, 这个时候会触发 GC。这个阈值会上下调整, 和 Metaspace 已经占用的操作系统内存保持一个距离
2. Metaspace 的总使用空间达到了 MaxMetaspaceSize 设置的阈值, 或者 Compressed Class Space 被使用光了, 如果这次 GC 真的通过卸载类加载器腾出了很多的空间, 否则的话, 我们会进入一个糟糕的 GC 周期, 即使我们有足够的堆内存

7. 运行时常量池 vs 常量池

- 方法区中, 内部包含了**运行时常量池**
- 字节码文件中, 内部包含了**常量池**
- 常量池: 存放编译期间生成的各种字面量与符号引用/可以看做是一张表, 虚拟机指令根据这张常量表找到要执行的类名/方法名/参数类型/字面量等类型
- 运行时常量池: 常量池表在运行时的表现形式
- 编译后的字节码文件中包含了类型信息, 域信息, 方法信息等, 通过 ClassLoader 将字节码文件的常量池中的信息加载到内存中, 存储在了方法区的运行时常量池中

### stack

![avatar](/static/image/java/javase-jvm-stack.png)
Expand Down
33 changes: 0 additions & 33 deletions java/se/jvm/readme.md
Original file line number Diff line number Diff line change
@@ -1,33 +0,0 @@
## cl

1. cl 图
2. cl 作用: 3
3. cl 种类 & jdk 实现集成
4. cl 加载过程: 加载 2 & 链接 [3] - 初始化 [4-3]
5. 初始化和实例化
6. 热加载
7. cl 加载顺序
8. 双亲委派机制
9. spi

## jvm

1. 图 1 + 线程图 2
2. 堆体系结构
3. 堆参数调优入门: -Xms==-Xmm 为什么要一样
4. GCRoot
5. 4 大垃圾回收算法: 特点 + 使用
6. 如何盘点查看 JVM 系统默认值
- 的参数类型: 3
- 盘点家底指令: 2
- 查看默认的逻辑回收器
7. 常用的优化参数
8. GCDetails 的查看
9. 强引用/软引用/弱引用/虚引用
10. OOM 的认识: 6
11. 垃圾收集器分类
12. 垃圾收集器有哪些
13. 如果选择垃圾收集器
14. jvm 配置垃圾回收器
15. 生产环境服务器变慢
16. CPU 过高怎么排查具体的排查过程
9 changes: 8 additions & 1 deletion java/se/thread-advance/Thread.md
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@
- 返回值: excute() 没有返回值 | submit() 存在返回值
- 异常: excute() 的异常信息会被 Thread.UncaughtExceptionHandler 处理 | submit 的异常信息会被封装到 Feature 内, 使用 get 会抛出
8. 线程池异常处理
- 手动 try..catch
- ThreadPoolExecutor#afterExecute
- UncaughtExceptionHandler: 不配置的话也会 log 出异常(默认只在控制台)
Expand All @@ -635,7 +636,13 @@
- Thread.setUncaughtExceptionHandler 设置当前线程的异常处理器
- Thread.setDefaultUncaughtExceptionHandler 为整个程序设置默认的异常处理器
- Future 的 get/join 可以把异常直接抛出来
- **CF 下的只能使用 exceptionally 中获取异常**
- **CF 下的只能使用 exceptionally 中获取异常**: 在内部被 catch 过
9. 线程池内线程出现非捕获异常: 线程池的稳定性和可靠性(不会使线程减少)
- 异常捕获: 线程池会捕获线程抛出的异常, 防止异常传播到线程外部导致程序中断
- 线程移除(即使指定线程的异常处理器): 异常发生后, 线程池会将出现异常的线程从线程池中移除, 以避免该线程继续执行其他任务
- 线程替换: 线程池会创建一个新的线程来替换被移除的异常线程, 以保持线程池的稳定性和预设的线程数量
#### 线程池-ThreadPoolExecutor
Expand Down
Empty file added java/se/v2/jvm/gc/gc.md
Empty file.
Empty file added java/se/v2/jvm/heap/heap.md
Empty file.
File renamed without changes.
71 changes: 71 additions & 0 deletions java/se/v2/jvm/metaspace/metasapce.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
### Method Area: PermGen space / Meta space

![avatar](/static/image/java/javase-jvm-jdk8-metadata.png)
![avatar](/static/image/java/javase-jvm-jdk7-metadata.png)

1. 非堆内存[元空间]和永久代通过使用 方法区 实现
2. jdk8 移除永久代的原因

- 因为永久代使用的是虚拟机的内存, 为永久代设置空间大小是很难确定的; 元空间直接使用物理内存且可以子调整[在 max 范围内]
- 对永久代进行调优是很困难的
- 更容易导致 Java 程序更容易 OOM, 永久代仍然使用的是 Java 虚拟机的内存
- 为融合 HotSpot JVM 与 JRockit VM 而做出的努力,因为 JRockit 没有永久代, 不需要配置永久代
- 可以在 GC 不进行暂停的情况下并发地释放类数据

3. 方法区的大小决定了系统可以加载多少个类:

- 如果系统定义的类太多可能会产生 OOM
- 关闭 JVM 就会释放方法区的内存

4. 特性

- 方法区(Method Area)同堆区一样, 是各个**线程共享**的内存区域
- 方法区内存可以是不连续的: 永久代逻辑和物理上都属于 heap
- 方法区的大小和堆空间一样可以动态调整[`元空间-XX:MaxMetaspaceSize=-1 无限制`]或者固定[永久代]

5. [存放内容](https://blog.csdn.net/Xu_JL1997/article/details/89433916): 类的元数据, 但是 Class 对象是存放在 heap 中的

- 运行时常量池
1. [常量池表]运行时常量池[引用]: **但是字符串常量池[1 个]在 heap 中, 字符串常量池本质是一个 hash 的 StringTable, value 还是引用**
2. JIt 的缓冲
- 类信息

1. 类型信息[存在于 Class 对象中]: 对每个加载的类型[Class/interface/enum/annotation], JM 必须在方法区中存储以下类型信息
- 全类名: 包名.类名
- 直接父类的全类名: interface/java.lang.Object 没有父类
- 类型的修饰符: public, abstract, final
- 类型直接接口的一个有序列表
2. 域信息: 类的属性/成员变量, 静态属性的值在 heap 中
- 类所有的成员变量相关信息[赋值语句]及声明顺序
- 域名称/域类型/域修饰符[pυblic/private/protected/static/final/volatile/transient]
3. 方法信息: 所有方法信息[包含构造方法], 声明顺序
- 方法名称
- 返回类型或 void
- 方法参数的数量和类型[按顺序]
- 修饰符: [public/private/protected/static/final/synchronized/native/abstract]
- 方法的内容字节码 bytecodes + 操作数栈 + 局部变量表及大小[abstract 和 native 方法除外]
- 异常表[abstract 和 native 方法除外]:每个异常处理的开始位置, 结束位置, 代码处理在程序计数器中的偏移地址, 被捕获的异常类的常量池索引
4. 类初始化代码: 静态初始化代码块 + 动态代码块
5. 方法的符号引用

6. 方法区的 GC 问题

- 在 Java7 及之前, HotSpot 虚拟机中将 GC 分代收集扩展到了方法区, 主要是针对常量池的回收和对类型的卸载
- 而在 Java8 中, 已经彻底没有了永久代, 通过一个存储于堆内的 DirectByteBuffer 对象作为对元空间引用的操作
1. 分配空间时: 虚拟机维护了一个阈值默认 windows-21M, 如果 Metaspace 的空间大小超过了这个阈值, 那么在新的空间分配申请时, 虚拟机首先会通过收集可以卸载的类加载器来达到复用空间的目的, 而不是扩大 Metaspace 的空间, 这个时候会触发 GC。这个阈值会上下调整, 和 Metaspace 已经占用的操作系统内存保持一个距离
2. Metaspace 的总使用空间达到了 MaxMetaspaceSize 设置的阈值, 或者 Compressed Class Space 被使用光了, 如果这次 GC 真的通过卸载类加载器腾出了很多的空间, 否则的话, 我们会进入一个糟糕的 GC 周期, 即使我们有足够的堆内存

7. 运行时常量池 vs 常量池

- 方法区中, 内部包含了**运行时常量池**
- 字节码文件中, 内部包含了**常量池**
- 常量池: 存放编译期间生成的各种字面量与符号引用/可以看做是一张表, 虚拟机指令根据这张常量表找到要执行的类名/方法名/参数类型/字面量等类型
- 运行时常量池: 常量池表在运行时的表现形式
- 编译后的字节码文件中包含了类型信息, 域信息, 方法信息等, 通过 ClassLoader 将字节码文件的常量池中的信息加载到内存中, 存储在了方法区的运行时常量池中

---

## reference

1. https://blog.csdn.net/weixin_45505313/article/details/114089053
2. [arthas oom](https://zhuanlan.zhihu.com/p/359329753)
Empty file.
45 changes: 45 additions & 0 deletions java/se/v2/jvm/question/interview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# interview

## cl

1. cl 图
2. cl 作用: 3
3. cl 种类 & jdk 实现集成
4. cl 加载过程: 加载 2 & 链接 [3] - 初始化 [4-3]
5. 初始化和实例化
6. 热加载
7. cl 加载顺序
8. 双亲委派机制
9. spi

## jvm

1. 图 1 + 线程图 2
2. 堆体系结构
3. 堆参数调优入门: -Xms==-Xmm 为什么要一样
4. GCRoot
5. 4 大垃圾回收算法: 特点 + 使用
6. 如何盘点查看 JVM 系统默认值
- 的参数类型: 3
- 盘点家底指令: 2
- 查看默认的逻辑回收器
7. 常用的优化参数
8. GCDetails 的查看
9. 强引用/软引用/弱引用/虚引用
10. OOM 的认识: 8
11. 垃圾收集器分类
12. 垃圾收集器有哪些
13. 如果选择垃圾收集器
14. jvm 配置垃圾回收器
15. 生产环境服务器变慢
16. CPU 过高怎么排查具体的排查过程

## 生产遇到的问题

1. oom: heap | metaspace

---

## reference

1. [oom analysis](https://zhuanlan.zhihu.com/p/561704557)
2 changes: 2 additions & 0 deletions java/se/v2/jvm/reamd.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[toc]

## jvm

1. jvm
Expand Down

0 comments on commit befbe8d

Please sign in to comment.