JVM
学习 JVM 可以帮助我们开发者更好地优化程序性能、避免内存问题
- 了解 JVM 的内存模型和垃圾回收机制,可以帮助我们更合理地配置内存、减少 GC 停顿
- 掌握 JVM 的类加载机制可以帮助我们排查类加载冲突或异常
- JVM 还提供了很多调试和监控工具,可以帮助我们分析内存和线程的使用情况,从而解决内存溢出内存泄露等问题
所以主要内容:内存模型、垃圾回收机制、类加载机制、JVM 调试/监控 工具
好好学习,天天向上
学习 JVM 可以帮助我们开发者更好地优化程序性能、避免内存问题
所以主要内容:内存模型、垃圾回收机制、类加载机制、JVM 调试/监控 工具
JVM 启动后,大致可以分为三个功能区:类加载器、运行时数据区以及执行引擎
内存区其实是功能区中"运行时数据区"的具体细分
JVM(功能区视角)
│
├── 类加载器
│
├── 运行时数据区 ←──── 这部分就是"内存区"
│ ├── 程序计数器
│ ├── 虚拟机栈
│ ├── 本地方法栈
│ ├── 堆
│ └── 方法区
│
└── 执行引擎
├── JIT 编译器
└── 垃圾回收器
当 Java 应用需要与操作系统底层或硬件交互时,通常会用到本地方法栈。
native 方法是在 Java 中通过 native 关键字声明的,用于调用非 Java 语言,如 C/C++ 编写的代码。Java 可以通过 JNI,也就是 Java Native Interface 与底层系统、硬件设备、或者本地库进行交互
Java 的 native 方法本身没有 Java 代码实现,而是交给本地代码实现
public native void test();
虚拟机栈、本地方法栈、程序计数器 | 堆、方法区
主要是方法区实现的不同
方法区是 JVM 规范里的概念, JVM 需要有这么一块区域来存类相关信息
HotSpot 实现层面:曾经用永久代、后来用元空间来实现
JDK 1.6 使用永久代来实现方法区:
JDK 1.7 时仍然是永久带,但发生了一些细微变化,比如将字符串常量池、静态变量存放到了堆上。
Java 没有 Ready 状态,线程状态有 6 种:
NEW 新建
RUNNABLE 可运行(包含 Ready + Running)
BLOCKED 阻塞(等待锁)
WAITING 等待(wait/join/park 等)
TIMED_WAITING 限时等待
TERMINATED 终止
以线程 A 发起读取磁盘文件为例
当线程 A 执行到读取文件的代码时,它其实是没有权限直接控制底层硬件的,必须向操作系统老大哥(内核)求助。
在主线程中通过 new 关键字(例如 new Object() 或 new ReentrantLock())创建一个锁对象时,这个对象是被分配在 JVM 的**堆(Heap)**内存中的
在 Java 内存模型中,每个线程有自己私有的虚拟机栈(用于存储局部变量表、方法出口等),但堆内存是所有线程共享的。只要子线程能够拿到这个对象的内存地址(引用),它就可以访问这个对象。
当主线程启动子线程时,通常会将这个锁对象的引用(相当于这把锁在堆内存中的真实地址)通过某种方式传递给子线程:
Hashtable的底层数据结构主要是数组加上链表,数组是主体,链表是解决hash冲突存在的。
HashTable是线程安全的,实现方式是Hashtable的所有公共方法均采用synchronized关键字,当一个线程访问同步方法,另一个线程也访问的时候,就会陷入阻塞或者轮询的状态。
本质就是构建了一个存储了 Entry<?,?> 对象的数组,数据就存放在具体的 Entry 对象里,对应的索引根据 hash 来算
| 类 | 作用 |
|---|---|
| Semaphore | 限制线程的数量 |
| Exchanger | 两个线程交换数据 |
| CountDownLatch | 线程等待直到计数器减为 0 时开始工作 |
| CyclicBarrier | 作用跟 CountDownLatch 类似,但是可以重复使用 |
| Phaser | 增强的 CyclicBarrier |
常用的有五种
BlockingQueue<E>