了解JVM内存模型,必先了解其内部各个部分的组成!
Java虚拟机在执行java程序的过程中会把它管理的内存划分为若干个不同的数据区域;这些区域各自都本身的用途,以及创建和销毁的时间,有些区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。其具体划分如下:
现在我们针对每个区域所起用途做个详细的说明:
- 程序技术器:线程私有,其可以看作是当前线程所执行的字节码的行号指示器;
- 线程执行得是java方法,计数器记录是正在执行的虚拟机字节码指令的地址;
- 线程执行得是Native方法,计数器值为空;
- 虚拟机栈:线程私有,描述是java方法执行的内存模型,每个方法在执行的同时都会创建一个栈桢用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直到执行完成的过程,就对应着一个栈桢在虚拟机栈中入栈到出栈的过程;
- 局部变量表存放了编译期可知的各种基本数据类型、对象引用(reference类型,不等于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)
- 本地方法栈:与虚拟机栈相似,其为虚拟机使用到的Native方法服务;
- Java堆:被所有线程共享的一块内存区域,在虚拟机启动时创建。其作用就是存放对象实例,所有的对象实例以及数组都要在堆上分配;
- 可划分为:新生代和老年代;
- 新生代还可划分为Eden空间、From Survivor空间、To Survivor空间;
- 方法区:被所有线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
- 运行时常量池:方法区一部分,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放;
- 字面量指文本字符串,final变量等。
- 引用量指类名和方法名等。 最常见的一种用法是在调用方法的时候,根据方法名找到方法的引用,并以此定位到函数体进进行函数代码的执行。
在继续学习JMM内容前,我们先来谈谈一道经典面试题:
String a = "abc";
String b = "abc";
int c = 1;
String d = new String("abc");
上述创建过程中,建立多少对象,在虚拟机中如何分配内存的?
1 String a = "abc";
虚拟机分别在虚拟机栈(下述称为栈内存)中的局部变量表创建一个a对象引用,方法区中常量池建立一个“abc”常量,a指向它;
2 String b = "abc";
同样在栈内存中局部变量表创建一个b对象引用,由于方法区中常量池已经有一个“abc”常量,b也指向它;
3 int c = 1;
由于基础数据类型直接在栈内存中局部变量表创建一个对象;
4 String d = new String("abc");
先在栈内存中局部变量表创建一个对象引用d,同时在堆中创建一个对象“abc”,d指向它;
对象上述问题分析过程,可以总结出我们日常开发操作对象的在JVM内存区域中存取方式如下:
通过上述问题,我们初步了解到JVM中每个内存区域的作用;但是还有一个问题,JVM所有的内存我们是否都可以进行管理的呢?
其实答案是很明显不是,JVM管理的就只有堆内存,我们所熟知GC回收也是针对于此;
好了,我们详细了解堆内存内部构造:
JVMHeap分代:
- Young Generation(新生代):
- 大部分对象都是朝生暮死,随生随灭的,GC选择了复制算法;
- Young分为3个区域,Eden所有新建对象都会存在于该区、两个Survivor区用来实施复制算法;
- 每次复制就是将Eden和第一块Survivor的活对象复制到第二块,然后清空Eden与第一块Survivor;
- Eden与Survivor的比例由-XX:SurvivorRatio=设置,默认为32;
- Old Generation(老年代):
- Young的对象如果能够挺过数次收集,就会进入年老代。其使用标记清理算法;
- -XX:MaxTenuringThreshold=设置熬过年轻代多少次收集后移入年老代;可以使用-XX:+PrintTenuringDistribution查看
注:
- GC用较高的频率对Young进行扫描和回收,称为minor collection;
- 同时对Young和Old的收集称为major collection;
那么什么时间进行GC回收呢?
- Minor GC(新生代回收)的触发条件比较简单,Eden空间不足就开始进行Minor GC回收新生代。
- Full GC(老年代回收,一般伴随一次Minor GC)则有几种触发条件:
- 老年代空间不足
- PermSpace空间不足
- 统计得到的Minor GC晋升到老年代的平均大小大于老年代的剩余空间