浅析Java内存区及其垃圾回收机制

浅析Java内存区及其垃圾回收机制

  • Java三大内存区
  • Java堆与栈的形象描述
  • 两种垃圾判别机制
  • 两种垃圾回收技术
  • JIT编译器技术简介

Java三大内存区

浅析Java内存区及其垃圾回收机制_第1张图片

Java堆与栈的形象描述


Java的堆比较特殊,《Java编程思想》(第4版)里把Java的堆(Java的堆是堆,Java的堆栈是栈)比作一个传送带,每分配一个新对象,它就往前移动一格。

但是其实这样的描述不够准确,因为这样的话会造成大量的空间浪费。我们可以设想,如果JVM真的像传送带一样实现堆,那么即使一个对象不在被使用,其存储空间也不会被释放。我们可以这样理解Java的堆:

  • Java里的堆是面向JVM实例的,由运行在此JVM实例上的所有线程共享的,用来存放实例对象(包括数组和new String()方式创造的字符串)的一块内存空间。
  • Java的堆是一种动态内存分配的抽象描述,而不是一种具体的数据结构,其具体实现依赖于具体的Java虚拟机。
  • 由于Java堆的内存管理效率很高,我们可以把Java的堆抽象成一个优化的栈(只有GC能弹出数据的栈)。
    C++的堆无法抽象成栈主要是因为其没有独立于用户程序的垃圾回收机制,每一块分配出去的存储实例对象的内存都要由其自身管理(包括销毁)。这也就是说难以实现对C++堆的整体内存再分配,所以如果把C++的结构抽象为栈这一数据结构的话,那么很难保证C++的堆不会满。而Java则不同了,其具有一个自动的,面向于JVM的垃圾回收机制(相当于MySQL 里的OPTIMIZE TABLE对表的作用);通过GC,那么我们可以利用虚拟机自动实现栈中空间的重新整理,并对Java栈中这些实例对象的引用变量的值进行自动更新(这也是Java引用与c的指针的区别之一)。

  • 同一个调用栈里存放Java方法的栈帧与native方法的栈帧
  • 栈中存放一些基本类型的变量和对象的引用变量。当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
  • 栈中的变量可以被多个引用变量连接。比如我们给一个int型变量i赋值1的时候,JVM会在栈中寻找是否有一个值为1的整数,有的话就把这个基本类型内存空间与i关联。与对象引用不同的是,把一个新值赋值给基本变量时,JVM通过改变引用指向的内存空间来改变其值。就是说,如果给i赋值2,那么JVM先查找栈中是否有2,有的话修正引用,而非存储1的那个内存单元;没有的话就把2压栈。
  • 下面说一下两种垃圾判别机制

    引用计数 

    特点 描述
    发生时间 程序生命周期。
    方式 每个对象都有一个引用计数器,当引用离开作用域或被置为null时减一,当对象被连接到一个新引用变量上时,计数器加1。当对象引用计数器为0时,释放对象。
    优点 思想简单。
    缺点 当出现循环引用的情况时,无法及时回收相关对象;且JVM判断循环引用的开销较大。

    可以使用冒号来定义对齐方式:

    追溯堆栈或静态存储区活引用法
    这种方法,就是从堆栈和静态存储区开始,遍历所有引用,对于发现的每个对象,再遍历此对象所包含的所有引用,反复进行。类似于图的遍历,在这个图里的所有节点(对象)都是活的,剩余的对象就可以被判别为回收了。而且,因为“引用计数”法中的交互引用对象几乎不会在堆栈和静态存储区中(而是随着对象存储在堆中)出现,所以几乎完全避免了这个现象。

    两种垃圾回收技术

    总括 《Java编程思想》(第四版中文版)关于JVM垃圾回收技术的概括:
    自适应的、分代的、停止-复制、标记-清扫的。

    我们先来介绍下停止-复制技术的步骤:
    1. 暂停程序运行(这点看出其不属于后台回收模式);
    2. 将堆中存活的对象从当前堆(或者是当前堆中的块),复制到另一个可用堆(或者是当前堆中可用的块)中;
    3. 原来的堆(块)中就只剩下垃圾,交给GC处理。
    注意:

  • 2中的实现方式依赖于具体的实现;
  • 当原来存活的对象被复制到新堆后,就又是一个接着一个紧密排列的了;
  • 当对象被复制时,其静态存储区和栈中的引用变量会被JVM修正,但是堆中对象里的引用会延迟到被遍历时才会修正(相当于有一张逻辑上存储新旧地址映射关系的表);
  • 当出现只有少量垃圾的情况时,每次都采用停止-复制模式的话,开销太大;
  • 于是,引出了标记-清扫方式
    1. JVM从静态存储区和栈开始遍历所有引用,标记其中所有获得引用;
    2. 之后,标记工作结束时,JVM回收没有被标记的对象。但是,不发生对象复制,所以会节省空间和时间,但并没有起到使对象紧凑排列的作用。

    自适应
    JVM会监视垃圾回收效率,选择并切换这两种方式进行垃圾回收。

    分代
    Java虚拟机的分代比较复杂,可以参考这篇文章。

    JIT

    可以参考这篇文章,哈哈!偷个懒,这两个东西要说的太多了!。

    你可能感兴趣的:(JVM,Java,堆栈,栈,垃圾回收)