Java学习笔记-JVM内存管理

来源:互联网 发布:python删除excel数据 编辑:程序博客网 时间:2024/05/16 06:25

一、Java内存区域

Java虚拟机把运行时数据区划分为几个不同的区域。

线程私有的,即每一条线程都会有自己独立的内存空间,有以下几个部分:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈

所有线程共享的内存空间,包括:

  • 方法区

1、线程私有数据区

程序计数器

程序计数器比较小,保存当前线程所执行字节码的行号,字节码解释器工作时就是根据计数器的值来执行的。每一条线程都有自己的计数器,且互不影响。如果在执行native方法,则计数器为空。

虚拟机栈

虚拟机栈描述的是java方法执行的内存模型。每个方法执行的时候,都会创建一个栈帧,用于保存局部变量等。因此局部变量也是保存在虚拟机栈中的,包括基本数据类型和对象引用。局部变量空间的大小在创建栈帧的时候就是确定的。这就是我们常说的jvm堆栈中的栈。

本地方法栈

它跟虚拟机栈的区别是,它为Native方法服务


2、所有线程共享数据区

堆用于存放对象实例和数组。也是垃圾收集器管理的主要区域。它在物理上可以不连续,但是在逻辑上是连续的

方法区

方法区用于存放类信息,静态变量,常量(特别地,运行时常量池),这块内存也会进行垃圾回收,主要是针对常量池的回收和类型的卸载。

运行时常量池(方法区的一部分)

存放编译时生成的字面量和符号引用。当然运行期间也可以将新的常量添加到池中,如String的intern方法。


3、直接内存

以上内存区域都是虚拟机运行时数据区的一部分,还有一块特殊区域是直接内存。这是NIO引入的,可以使用Native函数库直接分配堆外内存,通过DirecrByteBuffer对象对这块内存进行操作,它避免了Java堆和Native堆之间来回复制数据,提高了性能


4、对象访问

虚拟机的实现不同,产生了对对象的两种不同访问:句柄访问方式和直接指针访问方式。

句柄访问方式

句柄访问方式会将Java堆分为两部分,句柄池和实例池。Java栈中保存了对象的引用,引用指向了句柄池。句柄中保存了对象实例数据的指针和对象类型数据的指针。对象实例数据指针指向实例池(对象实例数据),对象类型数据的指针指向方法区(对象类型数据)

这种方式的优势在于:由于垃圾回收时会移动对象,句柄访问方式的句柄地址稳定。

直接指针访问方式

直接指针访问方式的Java堆是整体的。引用指向对象地址,该Java堆中的对象,拥有对象实例数据和对象类型数据的指针。

优势在于,节约了一次指针定位的时间开支,速度更快。


二、垃圾回收

垃圾回收主要指的是对堆中的对象进行回收。判断一个对象是否需要回收,使用根搜索算法。以一系列“GC Roots”的对象作为起点,从这些节点开始往下搜索,搜索走过的路径成为引用链,如果一个对象到GC Roots没有任何引用链,则该对象不可用。Java中,GC Roots包括以下几种

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区的类静态属性引用的对象
  • 方法区中的常量引用的对象
  • 本地方法栈引用的对象

当一个对象不可用时,该对象会被标记并且进行一次筛选。如果该对象没有覆盖finalize方法,或者finalize方法已经被虚拟机调用过一次,则该对象会判定为需要回收。否则,该对象会被放置到F-Queue对象中,并由虚拟机自动建立的、低优先级的Finalizer线程去执行,即触发finalize方法,但不承诺会等待它运行结束。


1、垃圾回收算法

标记-清除算法

首先,标记处所有需要回收的对象,回收时清除所有被标记的对象。这个算法有两个问题,一是效率低,二是有大量不连续的内存碎片。

复制算法(适用新生代)

复制算法会把内存划分为大小相等的两块,每次使用一块,当这一块内存用完以后,就将还存活着的对象复制到另外一块上,再将已使用的内存空间清理掉。

这里更好地算法是,把内存分为三块,一块Eden(占80%),两块Survivor(分别占10%),每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活的对象一次性拷贝到另外一个Survivor空间。如果Survivor空间不够,则依赖其他内存作为担保(老年代)。

标记-整理算法(适用老年代)

标记整理算法也需要标记对象,不过会将所有存活的对象移向一端,再直接清除边界外的内存。


当前虚拟机对对象的回收,采用分代手机算法。新生代中,大部分对象存活不高,选用复制算法,只需复制一小部分对象。老年代对象存活率高,可使用标记整理算法。


三、内存分配

从垃圾回收算法可知,堆内存分为4个部分,一部分用于存放老年代,另外三个部分(一个Eden,两个Survivor)用于存放新生代。

对象优先在Eden分配。

大对象直接进入老年代。

长期存活对象进入老年代。每个对象有一个年龄计数器,每经过一次Minor GC(新生代),如果存活,对象年龄增加1岁,到达一定年龄(默认15岁),对象会进入老年代。如果Survivor空间中相同年龄所有对象大小总和大于Survivor空间的一半,大于等于该年龄的对象直接进入老年代。



0 0
原创粉丝点击