Java内存管理机制详解
Java内存管理机制
本文将介绍Java虚拟机所管理的内存区域以及内存回收问题:
- 1、Java虚拟机所管理的内存区域
-
2、内存回收问题
<1>:常用垃圾收集算法
<2>:JVM如何判断一个对象已经消亡可以被回收
<3>:如何设置JVM参数
1、Java虚拟机所管理的内存区域
Java内存区域分为五部分:分别是方法区、虚拟机栈、本地方法栈、堆和程序计数器。
其结构图如下:
其中方法区和堆是所有线程共享的数据区。其他三部分是线程隔离的。
各个区域的具体情况如下:
- 程序计数器:
可以看作是当前线程所执行的字节码的行号指示器,类似组原中的计数器,指定下一条要执行的指令。 Java虚拟机栈:
线程私有,生命周期跟随着线程,虚拟机栈所描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧用于存储局部变量表,操作数栈,动态链表,方法出口信息等。本地方法栈:
为虚拟机使用的Native方法服务。Java堆
所有线程共享的一块内存区域,在虚拟机启动的时候创建,此区域的唯一目的是存放对象实例。Java堆是垃圾收集器管理的主要区域,收集器基本采用分代回收算法。- 方法区
各个线程共享的区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。总的来说,该区域类似C++中的静态存储区。
2、JVM内存回收问题(GC)
<1> 常用的基本垃圾回收算法
(1)标记-清除算法
首先标记出所有需要回收的对象,然后回收所有需要回收的对象。
缺点是会使内存不连续,无法分配大内存块
(2)标记-清除-压缩算法
这种垃圾回收算法对上一种进行了优化,内存回收后进行一次内存优化压缩,跟操作系统里的内存紧缩相似。
缺点是会造成内存间不停的拷贝复制,性能非常差。
(3)标记-清除-复制算法
这种垃圾回收算法首先将内存空间分为两块相同的区域A和B,在内存回收时将A中还存活的内存块复制到B中,然后一次性清空A。
缺点是:对内存的要求大一些,长期复制拷贝上也会受到影响。
这三种是基础的垃圾回收算法,Java中使用的是分代收集算法,主要根据对象存活期将内存进行划分为两部分:
新生代 | (3)复制算法进行回收 |
---|---|
老年代 | (2)标记-清除-压缩算法进行回收 |
<2> 如何判断一个对象可以被回收
(1)引用计数器法
思想十分简单,引用某一对象,计数器便加1,引用失效就减1,计数器为零的对象便是可以回收的。
Java并没有使用这种方法,因为不能很好解决循环引用的问题。
(2)通过根搜索算法
通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象没有任何引用链相连时,该对象即为不可达,无法引用该对象。
可以作为GC Roots的对象:
虚拟机栈(栈帧中的本变量表)中引用的对象 |
---|
方法区中的类静态属性引用的对象 |
方法区中的常量引用对象 |
本地方法栈中的JNI引用的对象 |
<3> 如何设置JVM中堆的大小以及年轻代中的Eden区和Survivor区
参数 | 含义 | 解释 |
---|---|---|
-xms | 初始堆大小 | 空余堆内存小于40%的时候,JVM会增大堆直到-xms的最大限制 |
-xmx | 最大堆大小 | 空余堆内存大于70%的时候,JVM会减小堆直到-xms的最小限制 |
-xmn | 年轻代大小 | |
-xxsurivorRatio | Eden区与Survivor区的大小比值 | 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 |