浅谈Java堆内存分代回收

概述

与C++不同的是:在Java中我们无需关心对象占用空间的释放,这主要得益于Java中的垃圾处理器(简称GC)帮助我们自动的进行对象占用空间的释放。

下面我们带着几个问题来学习:

  1. 堆内存是如何分代的?
  2. 各分代之间是如何配合工作的?

1、堆内存是如何分代的?

用一张图片来描述(面积大小不代表实际占用空间大小)

堆内存分为:年轻代(Young) + 老年代(Old),年轻代又分为:Eden区 + Survivor区 * 2。

通常年轻代中的各区比值为:Eden区:Survivor0 :Survivor1 = 8:1:1

要尽可能的让对象不进入Old区。

S0和S1默认情况下会动态的自动调整大小,可以使用`-XX:UseAdaptiveSizePolicy`来关闭动态调整

2、各分代之间是如何配合工作的?

以一个对象的在每个区之间的复制来描述这个问题,我们假定这个对象一直存活着。

当我们写一段如下代码时

User user = new User();

user对象首先被放入到Eden区,当Eden区满的时候会发生第一次Minor GC,这时垃圾收集器会在S0和S1中随机选择一个区(假设选中了S0)来存放Eden区剩余存活的对象。当Eden区再次满的时候会发生第二次Minor GC,这时垃圾收集器会把Eden区存活的对象 + S0中存活的对象复制到S1中,当Eden区再次满的时候会发生第三次Minor GC,这时垃圾收集器会把Eden区存活的对象 + S1中存活的对象复制到S0中,如此循环复制。

那么对象什么情况下会进入到Old区?

  • Eden区满时,在对象将要进入S0或S1中时,如果S0或S1存放不下Eden区中某个对象时,这个对象将被复制到Old区。
  • 如果一个对象在S0和S1中经历了制定次数的复制之后,会被复制到Old区。

顺便说一下:年轻代垃圾回收使用复制算法,老年代回收使用标记清除算法。

如有描述的不准确,麻烦指明一下,谢谢!

原文地址:https://www.cnblogs.com/wuqinglong/p/9310136.html

时间: 2024-11-05 13:30:27

浅谈Java堆内存分代回收的相关文章

浅谈Java的内存模型以及交互

本文的内存模型只写虚拟机内存模型,物理机的不予描述. Java内存模型 在Java中,虚拟机将运行时区域分成6中,如下图:              程序计数器:用来记录当前线程执行到哪一步操作.在多线程轮换的模式中,当当前线程时间片用完的时候记录当前操作到哪一步,重新获得时间片时根据此记录来恢复之前的操作. 虚拟机栈:这就是我们平时所说的栈了,一般用来储存局部变量表.操作数表.动态链接等. 本地方法栈:这是另一个栈,用来提供虚拟机中用到的本地服务,像线程中的start方法,JUC包里经常使用的

Java虚拟机:JVM内存分代策略

Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代.老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存分代策略. 为什么要分代? 堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的对象实例都存放在堆内存中.给堆内存分代是为了提高对象内存分配和垃圾回收的效率.试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费

第五章:JVM内存分代策略

① Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代.老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存分代策略. ②为什么要分代? 堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的对象实例都存放在堆内存中.给堆内存分代是为了提高对象内存分配和垃圾回收的效率.试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象

Java垃圾回收(二) 堆内存的分代回收

堆内存的分代回收 Java针对堆的垃圾回收,将堆分为了三个较小的部分:新生代.老年代.持久代.新生代主要使用复制和标记-清除垃圾回收算法,年老代主要使用标记-整理垃圾回收算法,因此java虚拟中针对新生代和年老代分别提供了多种不同的垃圾收集器. 1. 分代回收的依据: 对象生存时间长短:大部分对象在Young期间就被回收. 不同代采用不同的垃圾回收策略:对存活时间不同的对象分类,用不同的垃圾回收算法进行高效的有针对回收. 2. 堆内存的分代: Young代: 回收机制:因为对象数量少,所以采用复

浅谈Java中的栈和堆

人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数据,栈对应的英文单词是Stack 基本类型 引用类型变量 方法 Java的堆中存储以下类型数据,堆对应的英文单词是Heap 实例对象 在函数中定义的一些基本类型的变量(8种)和对象的引用变量都是在函数的栈Stack内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当

浅谈Java回收对象的标记和对象的二次标记过程_java - JAVA

文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 一.对象的标记 1.什么是标记?怎么标记? 第一个问题相信大家都知道,标记就是对一些已死的对象打上记号,方便垃圾收集器的清理. 至于怎么标记,一般有两种方法:引用计数和可达性分析. 引用计数实现起来比较简单,就是给对象添加一个引用计数器,每当有一个地方引用它时就加1,引用失效时就减1,当计数器为0的时候就标记为可回收.这种判断效率很高,但是很多主流的虚拟机并没有采用这种方法,主要是因为它很难解决几个对象之间循环引用的

Java堆内存中为什么有两个survival区及为什么与年轻代比例是1:1:8?

Java堆内存分为年轻代和老年代,其中,年轻代分为Eden区和survival区,survival又分为fromSurvival和toSurvival. 首先第一个问题:为什么要有Survival区?因为如果没有Survival区,Eden每进行一次MinorGC,存活对象送到老年代,当老年代被填满就会触发MajorGC,消耗大量时间.当有Survival区后,存活对象可以先被放到此处做一个缓冲,只有经过16次筛选还存活的对象才被移送到老年代,减少MajorGC的发生. 第二个问题:为什么设置两

浅谈java线程池

熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor.大家可能了解到它的原理,甚至看过它的源码:但是就像我一样,大家可能对它的作用存在误解...现在问题来了,jdk为什么要提供java线程池?使用java线程池对于每次都创建一个新Thread有什么优势? 对线程池的误解 很长一段时间里我一直以为java线程池是为了提高多线程下创建线程的效率.创建好一些线程并缓存在线程池里,后面来了请求(Runn

Java堆内存又溢出了!教你一招必杀技

JAVA堆内存管理是影响性能主要因素之一.堆内存溢出是JAVA项目非常常见的故障,在解决该问题之前,必须先了解下JAVA堆内存是怎么工作的. 先看下JAVA堆内存是如何划分的,如图: JVM内存划分为堆内存和非堆内存,堆内存分为年轻代(Young Generation).老年代(Old Generation),非堆内存就一个永久代(Permanent Generation). 年轻代又分为Eden和Survivor区.Survivor区由FromSpace和ToSpace组成.Eden区占大容量