Java 内存管理 堆和栈 GC 垃圾回收 Garbage Collection

euww1769 9年前

来自: http://blog.csdn.net//never_cxb/article/details/48174961


Java GC 垃圾回收 Garbage Collection

参加这篇博客
java 运行时内存分配 堆和栈区别

程序计数器(Program counter Register)

这是线程私有的, 标记线程执行到哪儿了, 线程切换了也可以回到它本来运行中断的地方

java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的, 为了线程切换后能到恢复到正确的执行位置, 每个线程都要有个独立的程序计数器


java 虚拟机栈

栈帧用来存放局部变量表 操作数栈 方法出口等

每一个方法从调用直至执行完成的过程, 就对应着一个栈帧在虚拟机栈中入栈和出栈的过程

局部变量表存放了编译器已知的基本数据类型, 对象引用

操作数栈也是以字长为单位的数组, 它只能进行入栈出栈的基本操作. 在进行计算时, 操作数被弹出栈, 计算完毕后再入栈.

本地方法栈

这是Native method 本地方法执行需要的栈

java 堆

分为新生代和老年代, 新生代空间小, 老年代空间大, 这些可以通过参数设置, 也可以设置这几个区域的垃圾回收策略

新生代朝生夕死, 适合用一个大区域, 2 个小区域来回收. 用”标记- 复制” 的方法回收, 减少碎片, 复制后留下来的区域整体情况, 可以得到一个连续的内存快

老年代是大对象存放的地方, 或者是新生代中熬了个几次回收的对象, 具体多少次可以设置

老年代可能100%存活, “标记- 复制”方法不适用, 需要用”标记- 整理”方法, 这是对”标记- 清除”方法的改进, 清除会带来碎片. 标记- 整理将存活的对象向一段移动, 然后清理掉边界以外的内存

Java 内存区域补充

线程共享的区域有 Java 堆(java heap) 和 方法区域(method area)
回收内存也主要针对这两个区域

java 堆

所有的对象实例以及数组都在堆上分配, 堆可以处于物理上不连续的区域

方法区

Method Area 存储已被虚拟机加载的类信息 常量 静态变量 即时编译器编译后的代码等数据

运行时常量池是方法区的一部分, 它存放编译器生成的各种字面量和符号引用

HotSpot 用永久代(Permanent Generation)实现方法区, 但现在改用 Native Memory 实现方法区

运行时常量池

class 文件除了有类的版本 字段 方法 接口等描述信息外, 还有一项信息就是常量池

它保存了编译器生成的各种字面量和符号引用

常见误解说法

给对象添加一个引用计数器, 每当有一个地方引用它时, 计数器+1;
当引用失效时, 计数器-1;
任何时刻计数器为0的对象就是不可能被引用的

可达性分析算法

通过 GC Roots 的对象作为起始点, 从这些节点开始往下搜索, 搜索走过的路径称为引用链(Reference Chain), 当一个对象到 GC Roots 没有任何引用链相连时(即 GC Roots 到这个对象不可达), 此时这个对象就是不可用的

可作为 GC Roots的对象

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 方法区中类静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中 JNI (即一般说的 Native 方法) 引用的对象

## 新生代(Young Generation) 老年代(Old Generation)##

新生代中, 每次垃圾回收都有大批对象死去, 可以使用复制算法, 只需要少量存活对象的复制成本就可以完成回收

老年代中, 对象存活率较高, 没有额外的空间对它进行分配担保, 必须使用”标记–整理”算法进行回收