本文试图从操作系统进程的角度解释 Java 虚拟机是什么:
java 是一个 windows 的命令行的外部命令,其实对应了一个应用程序,这个程序就是 javahome/jre/bin 中的 java.exe,java 这个应用程序启动的时候,windows 就启动了一个名为 java.exe 的进程,如下图:
因为我是在windows下面的命令行中启动的 java,所以在java.exe 进程树如下: explorer.exe —子进程—> cmd.exe—子进程—>java.exe 。
只要是操作系统的进程,操作系统都会给该进程分配相应的进程空间,拿linux来说进程空间有:
- 进程状态(State)
- 进程调度信息(Scheduling Information)
- 各种标识符(Identifiers)
- 进程通信有关信息(IPC:Inter_Process Communication)
- 时间和定时器信息(Times and Timers)
- 进程链接信息(Links)
- 文件系统信息(File System)
- 虚拟内存信息(Virtual Memory)
- 页面管理信息(page)
- 对称多处理器(SMP)信息
- 和处理器相关的环境(上下文)信息(Processor Specific Context)
- 其它信息
具体可以参考:linux内存模型总结
其中进程自身的代码和运行时逻辑上需要知道的信息主要保存在虚拟内存信息里面,它包含进程的地址空间,这个地址空间指向一个应用程序被分配得到的代码区、堆区、栈区,如下图:
windows的进程的内存空间结构可能有一点细微的差别:
├———————┤低端内存区域
│ …… │
├———————┤
│ 动态数据区 │
├———————┤
│ …… │
├———————┤
│ 代码区 │
├———————┤
│ 静态数据区 │
├———————┤
│ …… │
├———————┤高端内存区域
这样 java 虚拟机在系统内就有对应的进程空间了。这是从操作系统的角度来看 java 虚拟机内存空间的结构。结合 java 虚拟机自身的结构,如下图:
其中 Class Loader 和 Execution Engine 是 JVM 的两个功能模块,它们都含有上述的应用程序的三个内存模块代码区、堆区、栈区,Runtime Data Areas 则是 JVM 的可以在程序中读写的内存区域,所以我估计 Runtime Data Areas 是属于应用程序的堆区。
这样去推论有些不合理哈,因为 jvm 不同厂商有不同的实现,jvm 规范只能用来做 java 源程序语义上的的分析——虚拟机会做什么,而不能用来做源程序执行行为的分析——虚拟机到底怎么做,系能如何等。所以要指定 java 虚拟机对一个类做了啥,还是看 jvm 规范,而不能从下往上推。