转自 http://www.cnblogs.com/vamei/archive/2013/04/28/3048353.html
一
- Java是在JVM虚拟的内存环境中运行的。内存分为栈stack和堆heap
- Java中,JVM中的栈记录了线程的方法调用。每个线程拥有一个栈。在栈的frame中,保存有该方法调用的参数、局部变量和返回地址。
- Java的普通对象存活在堆中。
二
垃圾回收概念
- 垃圾回收(garbage collection,简称GC)可以自动清空堆中不再使用的对象。
- 垃圾回收是Java的一大特征。并不是所有的语言都有垃圾回收功能。
- C/C++中,并没有垃圾回收的机制。程序员需要手动释放堆中的内存。
- 垃圾回收实际上是将原本属于程序员的责任转移给计算机。使用垃圾回收的程序需要更长的运行时间。
Java垃圾回收
- 在Java中,对象的是通过引用使用的。
- 不再有引用指向对象,不可到达(unreachable)。
- 垃圾回收用于
释放不可到达对象所占据的内存
。这是垃圾回收的基本原则。 引用计数(reference counting)
,早起垃圾回收的机制。-
循环引用(cyclic reference):
两个对象互相引用,而且此时没有其它(指向A或者指向B)的引用,我们实际上根本无法通过引用到达这两个对象。 -
可到达:
以栈和static数据为根(root),从根出发,跟随所有的引用,就可以找到所有的可到达对象。一个可到达对象,一定被根引用,或者被其他可到达对象引用。
-
JVM实施
- JVM的垃圾回收是多种机制的混合。JVM会根据程序运行状况,自行决定采用哪种垃圾回收。 JVM不同版本实施的GC机制会有不小的差异。Java本身并没有规定JVM的GC实施方式。
mark and sweep
每个对象将有标记信息
,用于表示该对象是否可到达
。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到所有的可到达对象,并标记(mark)。随后,JVM需要扫描整个堆,找到剩余的对象,并清空这些对象所占据的内存
。copy and sweep
堆被分为两个区域,对象总存活于两个区域中的一个。当垃圾回收启动时,Java程序暂停运行。JVM从根出发,找到可到达对象,将可到达对象 复制到空白区域中并紧密排列
,修改由于对象移动所造成的引用地址的变化
。最后,直接清空对象原先存活的整个区域
,使其成为新的空白区域。
- 在新建对象时,“copy and sweep"可以提供大块的连续空间。因此,如果对象都比较"长寿”,那么适用于"mark and sweep"。如果对象的"新陈代谢"比较活跃,那么适用于"copy and sweep"。
- 分代回收
永久世代(permanent generation)
中存活的是Class对象
。这些对象不会被垃圾回收。年轻世代(young generation)
和成熟世代(tenured generation)
需要进行垃圾回收。年轻世代中的对象世代较近,而成熟世代中的对象世代较久。
- 年轻世代进一步分为三个区域
eden(伊甸)
:新生对象
存活于该区域。新生对象指从上次GC后新建的对象。from, to
: 这两个区域大小相等,相当于copy and sweep中的两个区域
。当新建对象无法放入eden区时,将出发minor collection
。JVM采用copy and sweep的策略,将eden区与from区的可到达对象复制到to区
。经过一次垃圾回收,eden区和from区清空
,to区中则紧密的存放着存活对象。随后,from区成为新的to区, to区成为新的from区
。- 如果进行minor collection的时候,发现
to区放不下,则将部分对象放入成熟世代
。另一方面,即使to区没有满,JVM依然会移动世代足够久远的对象到成熟世代。 - 如果
成熟世代放满对象
,无法移入新的对象,那么将触发major collection
。JVM采用mark and sweep
的策略,对成熟世代进行垃圾回收。