JVM(二):JVM内存和垃圾回收

1.JVM 运行时内存

JVM 运行时内存可以分为:

  • 新生代(约占1/3堆空间)

    • Eden区
    • From Survivor区
    • To Survivor区
  • 老年代(约占2/3堆空间)

  • 永久代(位于方法区)

A.新生代(复制回收)

新创建的对象会存放在这里,一般占1/3堆空间,因为运行时不断会有对象被创建,所以新生代会频繁地触发垃圾回收。新生代分为三个区。

Eden区

新创建的对象会存放在这个区域,当Eden区满的时候会触发 Minor GC进行垃圾回收,仍然存活的对象会被移动到From Survivor区或者To Survivor区。

From Survivor区和To Survivor区

这两个区必须保证有一个区是空的,在每当触发Minor GC时,Eden区和Survivor区中非空的那块中存活的对象会移动到空的Survivor区中。From Survivor区和To Survivor区是可以互换的。

例如,此时Eden区和From Survivor区中有对象并触发了Minor GC,存活的对象被移动到To Survivor区,并清除Eden区和From Survivor区的内存。

B.老年代(标记回收)

老年代有两种产生的途径:

  • 新生代的对象到了一定的年龄晋升为老年代
  • 新的对象创建的时候新生代区域内存不足以存下这个对象,直接分配到老年代。

当老年代区域满了之后,会触发Full GC,回收整个堆内存。

C.永久代

主要存放虚拟机加载的类的信息。

2.垃圾回收

触发GC之后,有两件事要做:

  1. 判断哪些对象是垃圾
  2. 对垃圾进行回收

A.判断垃圾

判断垃圾有两种方法:

  • 引用计数法
  • 可达性分析
引用计数法

对象被引用的时候计数加一,对象引用失效的时候计数减一,当计数为零的时候,说明对象没有被引用,于是被视为垃圾。

但是这个方法不能解决两个无用对象相互引用的情况,因此需要第二个方法可达性分析。

可达性分析

为了解决循环引用,设计了可达性分析,即根据目标对象是否和一些特定对象有关联,来判断目标对象是否为活动对象。

我的理解是,这些特定对象需要维持活跃的状态,只要对象和这些保持活跃的对象有关联,就说明目标对象有可能会被使用,还不能当作垃圾进行回收。
举个例子:

void function(){
  Object obj = new Object();
  ...
  obj = null;
}

在function()方法中,定义了局部变量obj,在将obj引用赋值null之前,obj的引用一直存放在栈帧中,一直能被使用直到变为null或者方法结束被回收,这种对象在失效前就是活跃的。

这种特定的对象有几种:

  • 方法中局部变量的对象的引用
  • 常量池中的对象引用
  • 本地方法中的对象引用
  • 类的Class对象

只要能和这些特定的对象关联,就不会被视为垃圾,这个也解决了循环引用的问题。

B.回收算法

复制回收算法

新生代主要采取的回收算法。

将内存划为两块A和B,其中B块要保证为空,当A块的内存满了以后,将A内存中不是垃圾的对象复制到B中,并清除A的内存。

这种方法不容易产生内存碎片,但是要保证有一块内存是空闲的,在垃圾少,存活对象很多的情况下效率较低,所以适合垃圾较多,存活对象较少的新生代。新生代会将Eden区和其中一个Survivor区的存活对象复制到另一个空闲Survivor区,并清除Eden区和有垃圾的那个Survivor区。

标记回收算法(也叫标记整理算法)

老年代主要采用的回收算法

将内存中的垃圾进行标记,将存活的对象移动到内存的一端(减少产生内存碎片),之后清除存活对象外的内存。

这种方法因为要进行对象的转移,在回收大量对象的时候效率较低,所以适合垃圾较少的老年代。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值