第2章 Java内存区域与内存溢出异常
Java运行时数据区域
程序计数器(Program Counter Register)
一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器。
虚拟机栈(VM Stack)
与程序计数器一样,Java虚拟机栈也是线程私有的,和线程的生命周期相同。虚拟机栈描述的是Java方法执行的内存模型,每个方法在执行时都会创建一个栈帧(Stack Frame)用于存储局部变量。操作数栈、动态链接、方法出口等信息。这里所说的栈就是我们经常说的栈内存。
本地方法栈(Native Method Stack)
和虚拟机栈非常相似,虚拟机栈为虚拟机执行Java方法服务,本地方法栈为执行本地方法服务。
堆(Heap)
Java堆是Java虚拟机所管理的内存中最大的一块,被所有的线程共享,在虚拟机启动时自动创建。Java虚拟机规范中这样描述:所有的对象以及数组都要在堆上分配,但随着JIT编译器的发展,慢慢的会有一些变化。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为"GC"堆。从内存回收角度看,由于现在收集器基本都采用分代收集算法,所以Java堆还可以细分为:新生代和老年代;再细致一点有Eden空间,From Survivor空间、To Survivor空间。
方法区(Method Area)
和Java堆一样,方法区也是哥哥线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它也有一个别名 叫Non-Heap(非堆),可能是为了和Java堆区分开来
2.2.6 运行时常量池
运行时常量池也是方法取得一部分。Class文件中处理有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池 (Constant Pool Table),用于存放编译期产生的字面量和符号引用,这些内容是在类加载后存放在方法区的运行时常量池中。Java虚拟机规范没有对运行时常量池做任何细节要求。
第3章 垃圾收集器与内存分配策略
在谈到垃圾收集(Garbage Collection,GC)时,我们关心3件事情
- 哪些内存需要回收?
- 什么时候回收?
- 怎么回收?
在Java堆里存放着Java世界几乎所有的对象实例,垃圾收集器在对堆进行垃圾回收之前,首先要判断那些对象还活着,哪些对象已经死去(即不可能再被任何途径使用的对象)。
引用计数器算法
当对象刚刚创建的时候,给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。引用计数算法实现很简单,判定效率也很高,在大部分情况下是一个不错的算法,但是在主流的Java虚拟机里没有使用引用计数算法来管理内存的,其中最主要的原因是它很难解决兑现之间相互循环引用的问题。