3分钟掌握Diablo Edit2:暗黑2存档修改器的终极解决方案
2026/7/4 19:46:49
每运行一个Java程序,都会启动一个独立的JVM实例。但这里有几种情况和细节需要理解。
每个Java程序 → 启动一个Java进程 → 创建一个JVM实例例如:
java -jar app1.jar→ 启动一个进程,创建一个JVMjava -jar app2.jar→ 启动另一个进程,创建另一个独立的JVM命令行执行 java MainClass ↓ 操作系统创建新进程 ↓ 进程中加载JVM(jvm.dll/libjvm.so等) ↓ JVM初始化(分配堆、栈、方法区等内存) ↓ JVM执行MainClass.main()方法 ↓ 程序运行在独立的JVM环境中操作系统内存: ┌──────────────────────────────────────────────────┐ │ 进程1:JVM实例1 │ │ ┌──────────────────────────────────────────────┐ │ │ │ Java堆、栈、方法区等 │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ 进程2:JVM实例2 │ │ ┌──────────────────────────────────────────────┐ │ │ │ Java堆、栈、方法区等 │ │ │ └──────────────────────────────────────────────┘ │ │ │ │ 其他进程... │ └──────────────────────────────────────────────────┘有一些特殊场景,多个"程序"可能共享同一个JVM:
单个Tomcat进程(一个JVM) ├── Web应用1 ├── Web应用2 └── Web应用3你可以通过以下方式验证:
# 查看Java进程tasklist|findstr java# 或jps -l# 查看Java进程psaux|grepjava# 或jps -l# 启动第一个程序,设置堆内存为512Mjava -Xmx512m -jar app1.jar# 启动第二个程序,设置堆内存为1Gjava -Xmx1024m -jar app2.jar# 两个程序会使用各自配置的内存大小,互不影响一个JVM实例 ├── 线程1(有自己的栈、PC寄存器) ├── 线程2(有自己的栈、PC寄存器) ├── 线程3(有自己的栈、PC寄存器) └── 共享的堆内存、方法区每个JVM实例都会消耗:
内存开销:
CPU开销:
启动时间:
优点:
缺点:
新的技术如GraalVM Native Image可以将Java程序编译成本地可执行文件:
# 将Java程序编译为本地可执行文件native-image -jar app.jar app# 直接运行,无需启动完整的JVM./app| 场景 | JVM实例数 | 特点 |
|---|---|---|
| 运行独立Java程序 | 每个程序一个JVM | 完全隔离,独立配置 |
| Web服务器多应用 | 一个JVM(服务器进程) | 共享堆,类加载器隔离 |
| 微服务架构 | 每个服务一个JVM | 完全隔离,独立部署 |
| 容器化部署 | 每个容器一个JVM | 资源限制,进程隔离 |
# 为每个JVM合理设置内存java -Xms256m -Xmx512m -jar app.jar# 监控JVM资源使用jstat -gc<pid>1000# 每秒查看GC情况jmap -heap<pid># 查看堆内存使用默认情况下,每个独立的Java程序都会启动一个专门的JVM实例,这是Java"一次编写,到处运行"特性的基础实现方式。这种设计提供了良好的隔离性和灵活性,虽然有一定的资源开销,但确保了程序的稳定性和可维护性。
在实际生产环境中,根据应用架构的不同(单体应用、微服务、Web应用服务器等),JVM的部署方式会有所调整,但基本原理保持不变:一个Java进程对应一个JVM运行时环境。