java回收内存_深入浅出理解 java程序垃圾回收机制

什么是垃圾( Garbage) 呢?

垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。外文: An object is considered garbage when it can no longer be reached from any pointer in the running program.如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。甚至可能导致内存溢出。为什么需要GC

对于高级语言来说,一个基本认知是如果不进行垃圾回收,内存迟早都会被消耗完,因为不断地分配内存空间而不进行回收,就好像不停地生产生活垃圾而从来不打扫一样。除了释放没用的对象,垃圾回收也可以清除内存里的记录碎片。碎片整理将所占用的堆内存移到堆的一端,以便JVM将整理出的内存分配给新的对象。随着应用程序所应付的业务越来越庞大、复杂,用户越来越多,没有GC就不能保证应用程序的正常进行。而经常造成STW的GC又跟不上实际的需求,所以才会不断地尝试对GC进行优化。早期垃圾回收

在早期的C/C+ +时代,垃圾回收基本上是手工进行的。开发人员可以使用new关键字进行内存申请,并使用delete关键字进行内存释放。比如以下代码:

MibBridge *pBridge = new cmBaseGroupBridge ();//如果注册失败,使用Delete释放该对象所占内存区域if (pBridge->Register (kDestroy) != NO_ ERROR)delete pBridge;

这种方式可以灵活控制内存释放的时间,但是会给开发人员带来频繁申请和释放内存的管理负担。倘若有一处内存区间由于程序员编码的问题忘记被回收,那么就会产生内存泄漏,垃圾对象永远无法被清除,随着系统运行时间的不断增长,垃圾对象所耗内存可能持续上升,直到出现内存溢出并造成应用程序崩溃。

1、Serial (old)收集器

这个收集器是一个单线程收集器, 在他进行垃圾收集时, 必须暂停其他工作线程, 直到它收集结束 . (Stop The World)

新生代采用复制算法, 暂停所有用户进程

老年代采用标记 - 整理算法, 暂停所有用户线程

Serial收集器运行示意图

5e32ecbedffbef1e866e72c66fc679e8.png

2、ParNew收集器

ParNew收集器实质上是 Serial 收集器的多线程并行版本,

ParNew除了支持多线程并行收集之外, 其他与Serial 收集器相比起来没有太多创新之处 .

并行和并发概念补充:

并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续运行,而垃圾收集器运行在另一个 CPU 上。垃圾回收的多条线程并发来执行垃圾回收, 垃圾回收线程与用户线程是并行, 垃圾回收时, 用户线程是等待的 .

ParNew收集器运行示意图

c8ccfcd47ec30f886958d94c7fcdfa43.png

3、Parallel Scavenge (old) 收集器

Parall Scavenger 收集器也是一款新生代收集器, 它同样是基于 标记 - 复制算法实现的多线程并行收集器 .

Parall Scavenger 收集器 的特点是它的关注点与其他收集器不同 , CMS 等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间, 而 Parall Scavenger 收集器 的目标是达到一个 可控制的吞吐量 .

所谓吞吐量就是处理器用于运行用户代码时间与处理器总消耗时间的比值 .

4、CMS收集器

CMS (Concurrent Mark Sweep) 收集器是一种以获取最短停顿时间为目标的收集器 ,

CMS(Concurrent Mark Sweep)收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。

CMS 收集器是 基于标记 - 清除算法实现的, 整个过程分为四个步骤 :

初始标记 标记一下 GC Roots 能直接关联到的对象 速度很快并发标记 从 GC Roots 的直接关联对象开始遍历整个对象图的过程, 这个过程耗时较长但是不需要停顿用户线程 ,可以与用户 线程并发运行.重新标记 为了修正在并发标记期间, 因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录. 这个阶段的停顿时间会比初始标记阶段长些, 但也远比并发标记阶段的时间短.并发清除 清除掉标记阶段判断已死亡的对象, 由于不需要移动存活对象, 这个阶段也是并发执行的 .初始标记 和 重新 标记仍然需要 Stop The World

63b914d79fa05d1bb9ae66f13f86cc9c.png

5、Garbage First 收集器 (G1)

G1 不在坚持固定大小以及固定数量的分代区域划分, 而是把连续的 Java 堆分成了多个大小相等的独立区域 ( region ),每一个 region 都可以根据需要, 扮演新生代的 Eden Survivor空间 或者 老年代空间 . 收集器根据对扮演不同角色的 Region 采用不同的策略去处理 . Region 中还有一类特殊的 Humongous 区域, 专门用来存储大对象 . G1 认为只要超过 region 的一半即可判断为大对象 .

虽然 G1 保留了新生代 和老年代的概念, 但是新生代和 老年代不再是固定的了.他们都是一系列区域(不需要连续)的动态集合

四个步骤 :

初始标记 标记 GC Roots 直接关联的对象并发标记 扫描整个堆的对象图, 找到要回收的对象最终标记 短暂的暂停, 处理并发标记后仍遗留下来的最后那少量的 STAB 记录筛选回收 负责更新Region的统计数据, 对各个 Region 的回收价值和成本进行排序 . 必须暂停用户线程Java 基础知识 Java 基础知识疑难点/易错点

4c8772e2ee5b5644c70153afede534fe.png

实战 : 内存分配与回收策略

大多数情况下, 对象在新生代 Eden区中分配 . 当 Eden 中没有足够的空间进行分配时, 虚拟机会发起一次 Minor GC

大对象就只是需要大量连续内存空间的 Java 对象, 大对象直接进入 老年代.

长期存活的对象将进入老年代 ( 15 )

Survivor 空间中相同年龄所有对象大小的总和大于 Survivor 空间的一半, 年龄大于或等于该年龄的对象直接进入永久代

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值