JVM中的垃圾回收

1.为什么要有垃圾回收?

例如在C语言中,通过malloc在堆(和JVM的堆不太一样)里申请内存之后,就得再通过free手动释放内存空间,或者等到程序结束才会释放,如果忘记释放就可能会导致"内存泄漏"

内存泄漏:内存越用越多,可以用的空间越来越少,,空间逐渐用完,程序就会出现问题.

所以申请空间之后就得靠人为记得手动释放空间,但是只要涉及到人为,就会有不靠谱的时候,所以JVM就实现了垃圾回收这样的机制(garbage collection)简称GC.

2.垃圾回收主要回收哪个内存区域?

栈:栈里面是放的是局部变量,它们出了自己的作用域之后就自动回收了,所以不用刻意去回收.

程序计数器:每个线程有一个,所需空间是固定的,在线程销毁的时候跟着销毁就行了.

方法区:放的是类对象,主要的工作是"类加载",而很少涉及"类卸载",所以需要GC不必太迫切.

堆:这里放的是new出来的对象,这里是GC最主要的工作地点.new出来的对象用完之后就需要回收.

 3.JVM怎么知道谁是垃圾呢?

在垃圾回收中有两个典型的判定方法:1.引用计数 2.可达性分析

在JVM中使用的是可达性分析

什么是可达性分析呢?

就是我们设置一些起点作为GCRoot,从这些GCRoot开始去寻找可以访问到的对象,将他们标记为"可达",当这些标记完之后,剩下的那些就是"不可达"的也就是需要回收的垃圾了.

哪些可以作为GCRoot呢?

1.局部变量表中的局部变量  (每个线程中有一个栈,每个栈中有很多栈帧,每个战帧里有一个自己的局部变量表)

2.常量池中的对象

3.方法区中静态引用类型的成员

什么是引用计数呢?

就是使用额外的计数器记录一个对象被多少个引用指向.如果有新的引用指向这个对象,那引用计数就+1,如果有指向这个对象的引用有减少,则计数也会跟着-1.直到计数为0的时候就意味着没人引用它,也就成了垃圾了.此时就会被回收.

但是引用计数有两个比较大的问题:

1.对象如果不大,空间成本高

假如这个对象比较大的话就没什么问题,假设这个对象是1000Byte,程序计数器是4Byte

那加起来也就1004Byte

但是如果这个对象很小,只有2Byte,那加上计数器(4Byte1)就是6Byte,是原来的3倍大,空间成本太高辣!

2.有循环引用的问题

 在下面的操作之后就会有循环引用的问题.

 

两个对象现在相互引用了,这样计数器既不是0,也拿不到对象了,就会一直占着内存.我们就称为循环引用.

4.垃圾回收的过程

 但是这种清理方法会形成"内存碎片",内存并不是连续的,但是以后new对象的时候要的是连续的空间,所以这样清理出来的空间也不太能用.

解决方法使用"复制算法"也就是将标记的对象复制到另外一片内存上,再将原来的整片内存清空

 这种方法有点类似顺序表的删除操作,优点是可以有效解决"内存碎片问题",缺点是有点耗时.

 

典型的垃圾回收器:Serial,   ParNew,   Parallel,   Serial Old,   Parallel Old,   CMS,   G1   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值