整体了解 JDK & JVM
首先要对官方的 SDK 有点认识,同时要明白下面的概念:
- Java SE(Java Platform, Standard Edition):它是 Java 的标准版,主要用于桌面应用开发,同时也是 Java 的基础,它包含 Java 语言基础、JDBC(Java 数据库连接性)操作、I/O(输出输出)操作、网络通信、多线程等技术。
- Java EE(Java Platform, Enterprise Edition):它是 Java 的企业版本(javax..*),包含了 Servlet、JSP、JMS、JNDI 等的扩展。
- Java ME(Java Platform, Micro Edition):一般是指 Java ME Embedded,Java 微型版本,一般做嵌入式开发用。
- JRE(Java Runtime Environment),Java 运行环境。
- JDK(Java Development Kit),Java 开发者工具集,是用来编译和执行 Java 程序必备的 Java 开发环境,现在我们一般说 JDK 就是指的 Oracle 的 Java SE。因为 Sun JDK 和 Open JDK、JRockit 都被 Orcale 收购了,一统了江湖。
我们看下 Oracle 官方的图,如下:

这样我们对 JDK、JRE,有了概念上的认识之后,我们来看下我们的 JVM(Java Virtual Machine)——Java 虚拟机,也就是 HotSport 了。
Oracle 也出了 JVM 的规范。
Java 内存模型
Java 内存模型是理解 Java 多线程和 Java GC 必须要了解的抽象知识点,我们可以通过工具来更好的掌握 Java 内存模型。我给大家一个点:“我们通过不同的视角来理解内存模型”。我们可以通过不同的视角来理解内存模型。因为 JVM 类里面实际的内存操作远比我们想象得要复杂,因为这部分代码是 Oracle 官方的核心机密,没有对外公开,我们也只能通过官方文档及其 Jdk/bin 目录下面的工具来做到整体认识。
站在理解线程的视角看内存模型
我们可以把 JVM 内存结构直接分成线程私有内存和共享主内存。这样我们就可以很好地理解多线程的很多问题如同步锁、lock、validate 关键字,及其 ThreadLocal。这部分内容如果还疑惑的可以看作者的另外一篇 Chat:Java 多线程与并发编程 · Java 工程师必知必会。
我们从内存设置的角度出发

我们可以将内存直接分位堆内存、非堆内存(JDK8 以后叫 Metaspace,元空间)和其它,三个大的类别。
我们来看一下 JConsole 和 JVisualVM。
java/bin/jconsole 打开以后界面如下:

java/bin/jvisualvm 打开以后界面如下:

利用 tools,也可以看到 Java 工具也是简单的将其分成堆和非堆(Metaspace)。
而其它是什么呢?
Other 指的是“直接内存”,如一些(IO/NIO),这些 JVM 控制不了(如果线程变多线程栈吃的内存也会变的非常大,不可设置)。
对应的 JVM 设置的参数是:
- Xmx4g:JVM 最大允许分配的堆内存,按需分配;
- Xms4g:JVM 初始分配的堆内存,一般和 Xmx 配置成一样以避免每次 gc 后 JVM 重新分配内存;
- XX:MetaspaceSize=64m 初始化元空间大小;
- XX:MaxMetaspaceSize=128m 最大化元空间大小。
Metaspace 建议大家不要设置,一般让 JVM 自己启动的时候动态扩容就好了,没必要自己去设置。如果不动态加载 class ,当启动起来的时候,一般是很少有变化的。
从这个角度我们可以认为我们的 JVM 内存的大小是堆+metaspace+io(运行时产生的大小)。
我们从 JVM 的运行期的视角来看
可以分为五大部分:方法区、堆、本地方法栈区、PC 计数器、线程栈。我们也可以看下面的图,PC 计数器和栈、本地方法栈,是随着当前的线程开始而开始,销毁而销毁的。
我们再通过下面这个图理解一下这五个区和线程的关系:
对应的 JVM 的参数为 Xss512k,用来设置每个线程的堆栈大小。
从垃圾回收机制的视角来看

全局分代收集器,我们通过 java/bin/jvisualvm 来观察一下:
通过 JVisualVM 我们可以看得出来:
- 内存直接被垃圾收集器切分了5个部分:metaspace(class 结构)(永久代)、Old(老年代)、新生代(一个 Eden(新对象创作的乐园,老外真会取名)、二个 Survivor Space))。
- 一个对象默认被交换了6次还没有回收掉就会被扔到老年区里面。
-XX:InitialTenuringThreshold=7
通过这