JVM内存分类
java 采用自动内存管理,程序员只需要申请使用,系统会自动检查无用的对象并回收。
-
线程私有内存
– 程序计数器(Program Gounter Register)
– Java虚拟机栈(JVM Stack)
– 本地方法栈(Native Method Stack) -
多线程共享内存
– 堆(Heap)
– 方法区(Method Area):包含运行时常量池。
1. 程序计数器(Program Gounter Register)
–一块存储当前正在执行的方法的小内存,每个线程都有。
– 当前方法为本地(native)方法时,pc值未定义(undefined)。
– 当前方法为非本地方法时,pc包含了当前正在执行指令的地址。
– 该区域不会发生OutOfMemoryError异常。
2. JVM栈(JVM Stack)
– 每个线程都有自己独立的java虚拟机栈。
– Xss设置每个线程堆栈的大小。
–Java方法的执行基于栈,方法的内容存在栈中。
– 当栈的深度超过虚拟机规定的深度,会引发StackOverFlowError异常。
- 本地方法栈(Native Method Stacks):存储native方法的执行信息。
3. 堆(Heap)
– 对象和数组是在堆上分配内存的。
– 垃圾回收的主要区域。
– 设置大小:
- Xms 初始堆值,Xmx 最大堆值。
– 引发异常。 - 内存不足:OutOfMemoryError异常。
4. 方法区(Method Area)
– 存储JVM已经加载类的结构,所有线程共享。
- 运行时常量池,类信息,常量,静态变量等。
– 内存不足的时候,发生OutOfMemoryError异常。
– 运行时常量池(Run-Time Constant Pool)
- Class文件中常量池的运行时表示。
- 属于方法区的一部分。
- 内存不足的时候,发生OutOfMemoryError异常。
5. 总结
JVM内存参数
-
JVM默认运行参数,根据操作系统,物理硬件的不同而不同。
使用-XX:+PrintFlagsFinal 显示VM的参数。 -
程序启动的两类参数:
– 程序参数:程序需要,存储在main方法的形参数组中。
– 虚拟机参数:更改默认配置,用以指导进程运行。
其中,
-X参数,不标准,不在所有的JVM上通用。
-XX参数,不稳定,容易变更,可能在之后的版本中会变化。
-
堆(heap):存放对象和数组。
– -Xms初始堆值,如-Xmx20M设置初始堆值为20M。
– -Xmx最大堆值。 -
JVM栈(JVM Stack)
– 线程私有,存放方法内容。
– -Xss最大栈值。
– 当方法多次调用(递归操作),且方法中有很多成员变量时,栈的空间很快就是爆满。
– 当线程中有许多成员变量时,多次启动线程,栈空间消耗很快。 -
方法区(Method Area)
– 存储类信息,常量池等。
1.8以后,名为元数据区,使用-XX:MetaspaceAize,-XX:MaxMetaspaceSize。设置大小。
JVM对象引用
-
JVM内置垃圾收集器
GC(Garbage Collector),自动清除无用的对象,回收内存。
使用System的gc方法。垃圾收集器在回收对象的时候调用,只被调用一次。 -
Java对象的生命周期
对象通过构造函数创建,但是java没有析构函数回收内存。
java定义对象存活离他最近的一对大括号中。 -
无用对象的判定
零引用,互引用等。 -
对象引用链
通过一系列的"GC Roots"的对象作为起点,从这些节点开始向下搜索,走过的路径称为搜索链,不在链上的对象被判定为无用对象。 -
GC Roots对象包括:
– 虚拟机栈中引用的对象。
– 方法区中静态属性引用的对象。
– 方法区中常量引用的对象。
– 本地方法栈中引用的对象。 -
强引用
如:
Object obj1 = new Object();
Object obj2 = obj1;
obj1 = null;
此时,开始申请的内存还有对象obj2指向,就不会被回收。
- 软引用
描述有用但并非必须的对象,如一些数据缓存。
在系统要发生内存溢出异常的时候,被回收。
JDK采用SoftReference类来实现软引用对象。
Object obj1 = new Object();
SoftReference<Object> obj2 = new SoftReference<Objct>(obj1);
obj1 =null;
- 弱引用
描述非必须对象,弱引用的对象在下一次垃圾回收时,就会被回收。。
JDK提供WeakReference类来实现弱引用。
Object obj1 = new Object();
WeakReference<Object> obj2 = new WeakReference<Objct>(obj1);
obj1 =null;
- 虚引用
引用关系最弱,随机可能被回收。JDK提供PhantomReference类来实现。
为一个对象设置需引用关系的唯一目的是这个对象被回收器收集时收到一个系统的通知。用于对象跟踪。
垃圾收集算法
垃圾收集算法:垃圾收集器回收垃圾的规则。
- 引用计数法
对每一个对象都使用一个引用计数器,有引用则计数器加1,当引用失效,计数器减1。回收计数器为0的对象。
该方法简单高效,但是无法识别对象相互循环引用的情况。
- 标记-清除
– 标记阶段,标记出所有需要回收的对象
– 回收阶段,统一回收被标记的对象。
该方法简单,但是效率不高,内存碎片。
- 复制算法
将内存等分为两部分,每次使用其中的一部分,当这部分用完了之后,将这部分还活着的部分复制到另一部分中去。然后把这部分内存空间清除。
优点:简单,高效。
缺点:可用内存减少,对象存活率高的时候复制操作多。
- 标记-整理
– 标记阶段:与“标记-清除”算法一样。
– 整理阶段:让所有或者的对象都向一端移动,然后直接清理掉端边界以外的内存。
优点:避免内存碎片,无需两块相同的内存。
缺点:计算代价大,标记清除+碎片整理。还需更新引用地址。
- 分代收集
根据对象的生命周期不同,将内存分为新生代和老年代。
– 新生代(Young Generation):存放声明周期较短的对象,新建对象先被放入新生代。
– 老年代(Tenured Generation):经过几次gc仍存活,则方放入老年代。
针对各个年代的特点采用不同的收集算法。
新生代:复制算法,老年代:标记清除或标记整理。
堆内存分配:
新生代分为eden区,survivor区,survivor区又分为from区和to区。且from区和to区大小相等。
- 堆参数设置
-Xms 初始堆大小
-Xmx 最大堆大小
-Xmn 新生代大小
-XX:SurvivorRatio设置eden区和from(to)区的比例。
-XX:NewRatio设置老年代与新生代的比例。
-XX+PrintGC/-XX+PrintGCDetails打印GC的过程信息。