- JVM在操作系统中启动时,先会向操作系统申请内存,再进行运行时数据区初始化,然后把类加载到方法区,再执行方法。
- 方法的执行和退出过程在内存上的体现就是虚拟机栈中栈帧的入栈和出栈。
- 同时在方法的执行过程中产生的对象一般都是放在堆中的,最后堆中的对象也是需要进行垃圾回收的,一般JVM调优主要是优化堆空间。
堆空间分代划分:
堆被划分为新生代和老年代(Tenured),新生代又被进一步划分为 Eden 和 Survivor 区,最后 Survivor 由 From Survivor 和 To Survivor组成。
GC 概念
GC- Garbage Collection 垃圾回收,在 JVM 中是自动化的垃圾回收机制,一般不用去关注,在 JVM 中GC的重要区域时堆空间,可以通过一些额外方式主动发起它,比如 System.gc() (切记不要使用,否则会被你队友打死的)
JHSDB 工具
JHSDB 是一个机遇服务性代理实现的进程外调试工具。服务性代理是 HotSpot 虚拟机中一组用于映射 Java 虚拟机运行信息的,主要基于 Java 语言实现的 API 集合
JDK1.8 的开启方式
JDK1.8启动 JHSDB的时候必须将 sawindbs.dll(一般会在jdk的bin目录下),复制到jre中bin目录下()
然后到目录: D:\B_02_Java\jdk1.8.0_181\lib 进入命令行, 执行 java -cp .\sa-jdi.jar sun.jvm.hotspot.HSDB
代码改造:
VM参数加入:
-XX:+UseConcMarkSweepGC
-XX:-UseCompressedOops
/**
* @author wangchl
* VM参数
* -Xms30m -Xmx30m -XX:MaxMetaspaceSize=30m -XX:+UseConcMarkSweepGC -XX:-UseCompressedOops
*
*
*/
public class JVMObject {
public final static String MAN_TYPE = "man"; // 常量
public static String WOMAN_TYPE = "woman"; // 静态变量
public static void main(String[] args)throws Exception {
Teacher T1 = new Teacher();
T1.setName("Mark");
T1.setSexType(MAN_TYPE);
T1.setAge(36);
for(int i =0 ;i<15 ;i++){
System.gc();//主动触发GC 垃圾回收 15次--- T1存活
}
Teacher T2 = new Teacher();
T2.setName("King");
T2.setSexType(MAN_TYPE);
T2.setAge(18);
Thread.sleep(Integer.MAX_VALUE);//线程休眠
}
}
class Teacher{
String name;
String sexType;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSexType() {
return sexType;
}
public void setSexType(String sexType) {
this.sexType = sexType;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
JHSDB 中查看对象
实例代码启动
因为 JVM 启动有一个进程, 需要借助一个命令 jps 查找到对应程序的进程
把进程ID复制到 Attach中去
查看堆参数:
上图中可以看到实际JVM 启动过程中对重参数的对照,可以看到,在不启动内存压缩的情况下。对内存里面的分代划分都是连续的。
再来查看对象
最后再对比一下堆中分代划分可以得出为什么 T1 在Eden,T2 在老年代
从上图可以验证栈内存,同时也可以验证到虚拟机站和本地方法栈在 HotSpot 中是合二为一的实现。
当通过Java运行以上代码时,JVM 的整个处理过程如下:
1、JVM 向操作系统申请内存时,JVM 第一步就是通过配置参数或者默认的配置参数向操作系统申请内存空间
2、JVM 获得内存空间后,会根据配置参数分配站、堆已经方法区的大小
3、完成以上步骤之后,JVM 首先会执行构造器,编译器会在 .java 文件被编译成 .class 文件时,收集所有类的初始化代码,包括静态变量赋值语句、静态方法块、静态方法、静态变量及常量放入方法区
4、执行方法。启动 main 线程,执行 main 方法,开始执行第一段代码。此时堆内存会创建一个 Teacher 对象,对象引用 student 就存放在栈中,执行其他方法时,具体的操作运行时数据区域
JVM深入辨析堆和栈

