新生代和老年代垃圾回收的细节

新生代和老年代

对象在被实例化之后,都是属于新生代。

大部分新生代的生命周期都是及其短暂的,例如在一个方法中创建的对象会随着方法执行完毕,栈空间的栈帧出栈后而失去引用。

而有一些对象确实会长期存活在堆内存的,比如被Static引用的对象。这种对象不会轻易的被垃圾回收器回收。

所以JVM会将堆内存分为两个区域,一个年轻代,一个老年代。

其中年轻代,顾名思义,就是创建和使用完之后立马就要被回收的对象放在里面。然后老年带呢,就是把一些会长期存活的对象放在里面。

为什么要分成新生代和老年代

很多人都会有一个疑问,为什么要划分两个区域呢?

因为这个垃圾回收有关,对于年轻代的对象,他们的特点是很快就会被回收,所以需要使用一种垃圾回收算法。

而对于老年代而言,里面的大部分对象可能都会长期存活,那么使用新生代的回收算法放在这里就可能并不是那么的合适。需要有着自己的一套回收算法。

什么是永久代

很简单,JVM里的永久代其实就是我们之前说的方法区

所谓的永久代,你可以认为是存放一些类的信息,在上一个章节我们知道我们生成的.class就是存放在这个区域的。一般情况下,我们对于jvm调优都是对新生代和老年代进行调优。一般而言永久代保持默认配置就可以了。

是不是意味着我们就不需要关注永久代?

肯定不是的。因为要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。最典型的场景就是,在 jsp 页面比较多的情况,容易出现永久代内存溢出。

如何判断一个对象是否是垃圾

我们知道,当一个对象被创建出来的时候,比如说在一个方法中创建一个对象,当该方法执行完毕后,就没有引用指向这个对象了,这个对象就会变成垃圾对象。

这仅仅是一种情况。

到低哪些对象是辣鸡,哪些对象不是?

JVM中使用了一种可达性分析算法来判定哪些对象是可以被回收的。这个算法的核心就是看这个对象有谁在引用它,然后一层一层的往上判断,看是否被GC roots所引用。

在java中,可作为GC Roots的对象有:

1.虚拟机栈(栈帧中的本地变量表)中引用的对象(也就是我们前面提到在方法中创建的对象);
2.方法区中的类静态属性引用的对象;
3.方法区中常量引用的对象;
4.本地方法栈中JNI(即一般说的Native方法)中引用的对象

当一个对象没有被上述所引用,那么这个对象就可以被认为是垃圾对象了。

总之记住一句话,只要你的对象被方法的具备变量,类的静态变量给引用了,就不会回收他。

java中对象不同的引用关系。

1、强引用

就是被GC roots所直接引用的对象。只要是强引用关系,那么垃圾回收器是绝对不会回收这个对象的。

2、软引用

public class test{
    public static SoftReference<ReplicaManager> manager =
        new SoftReference<ReplicaManager>(new Replicamanager)
}

/**如上诉代码,实例对象被“SoftReference” 软引用类型的对象包装起来了,那么这个对象的引用就是软引用。

正常情况下是不会回收软引用对象的,但是如果你进行垃圾回收后,返现内存还是不够存放新的对象的时候,这个时候就会吧软引用的对象给回收掉
**/

3、弱引用

这个相对前两中使用的很少,与软引用类时,当一个实例对象被“WeakReference”弱引用的对象包装起来的时候,那么这个对象就是弱引用。
弱引用的生命周期就存在下一次垃圾回收之前,也就是说下一次垃圾回收会回收掉弱引用的对象。

4、虚引用

最弱鸡的一种引用,我感觉没什么作用。一个对象是不是虚引用对他本生的生命周期没有影响。该什么时候回收就什么时候回收。
设置他唯一的目的就是被回收的时候会得到一个系统通知,一般来说没什么卵用

finalize()方法的作用

到这里,我相信你应该清楚了哪些对象会被回收哪些对象不会被回收。

如果一个对象被GC Roots所引用,但是!!他如果是软引用或弱引用,那么也是可能会被辣鸡回收器给回收掉的。

在垃圾对象被回收的时候,会调用Object对象的finalize()方法。

我们来模拟一个辣鸡的自我救赎代码。

public class A{
    public static A instance;
    @Override
    protected void finalize() throws Throwable{
        A.instance = this;
    }
}

当对象被回收的时候,调用finalize方法,重新将GC Roots的变量引用指向自己,那么就不会被回收了。

这个基本上没人用,感觉就是一个sb才会写的代码。写出来就是给大家说出这个细节。

新生代对象是如何变成老年代对象的

长期存活的对象会多次躲过垃圾回收

躲过多少次Minor GC而没有被回收掉,我们就认为这个对象的年龄有几岁了,默认情况下,当一个对象10多岁的时候,就认为他是一个老人了。需要被转移到老年代去。

想想也正常,新生代的竞争压力这么大,老年对象还是早点去老年代比较好不与年轻人竞争资源。

特别大的超大对象直接不经过新生代就进入老年代

年轻代的的竞争本来就很大,你还要占用那么多资源,不行不行,你还是去老年代吧。

动态年龄判断机制

这一部分需要结合垃圾回收器的算法来讲,就是复制算法。我们在后面的章节会讲到,这里大概介绍一下。

我们一般会将新生代分为三个区域,一个Eden,两个Survivor。比例8:1:1.

生成的对象默认在eden区域。当发生一次Minor GC后,会将存活的对象复制到其中一个Survivor区域。当下一次GC后又会将存活的对象复制到另一块Survivor。这么做的好处是减少内存碎片。

当我们发生一次GC后,将存活对象放到其中一块survivor区域。发现其中的1岁,2岁,3岁的对象年龄加起来内存超过survivor区域的一半,就会把4岁以及4岁以上的对想转移到老年代。

GC后survivor区域存放不下

这个没办法,GC后都还存放不下一般来说要不是访问量激增,要么就是优化的不到位,所以只好将这写对象转移到老年代。

空间担保机制

在发生minor gc之前,虚拟机会检测 : 老年代最大可用的连续空间>新生代all对象总空间?

1、满足,minor gc是安全的,可以进行minor gc。

2、不满足,虚拟机查看HandlePromotionFailure参数:

(1)为true,允许担保失败,会继续检测老年代最大可用的连续空间>历次晋升到老年代对象的平均大小。若大于,将尝试进行一次minor gc,若失败,则重新进行一次full gc。

(2)为false,则不允许冒险,要进行full gc(对老年代进行gc)。

原文地址:https://www.cnblogs.com/zhxiansheng/p/11294529.html

时间: 2024-08-20 17:46:04

新生代和老年代垃圾回收的细节的相关文章

[Java] 新生代和老年代垃圾回收策略

一.新生代:采用复制策略 Eden块,连个survival块 回收的时候,将Eden和当前使用的survival块当中的存活的对象转移到另一块survival当中,清空Eden和当前使用的survival块. 二 .老年代:标记移动算法 由于变化不是很大,而且大部分都是长期活着的对象或者大对象,所以使用新生代中的survival块无法全部容纳.这里使用标记移动的策略. [1] http://www.admin10000.com/document/1671.html

Java GC、新生代、老年代

堆内存 Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象.在 Java 中,堆被划分成两个不同的区域:新生代 ( Young ).老年代 ( Old ).新生代 ( Young ) 又被划分为三个区域:Eden.From Survivor.To Survivor.这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收.堆的内存模型大致为: 从图中可以看出: 堆大小 = 新生代 + 老年代.其中,堆的大小可以通过参数 –Xms.-X

【转】Java中的新生代、老年代、永久代和各种GC

JVM中的堆,一般分为三大部分:新生代.老年代.永久代: 1 新生代 主要是用来存放新生的对象.一般占据堆的1/3空间.由于频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收. 新生代又分为 Eden区.ServivorFrom.ServivorTo三个区. Eden区:Java新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代).当Eden区内存不够的时候就会触发MinorGC,对新生代区进行一次垃圾回收. ServivorTo:保留了一次MinorGC过程中的幸存者.

堆中的新生代与老年代

1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用,这样就会对堆的所有区域进行扫描.而我们的很多对象都是朝生夕死的,如果分代的话,我们把新创建的对象放到某一地方,当GC的时候先把这块存"朝生夕死"对象的区域进行回收,这样就会腾出很大的空间出来. 2.年轻代中的GC     HotSpot JVM把年轻代分为了三部分:1

堆中新生代,老年代,溢出实例,设置永久区溢出

1.堆溢出 main: public class HeapOOM { public static void main(String[] args) { List<UserBean> users = new ArrayList<UserBean>(); while (true) { users.add(new UserBean()); } } bean: public class UserBean { String name; int age; } 然后在运行的时候设置jvm参数 -

java 虚拟机--新生代与老年代GC

Heap: JVM只有一个为所有线程所共享的堆,所有的类实例和数组都是在堆中创建的. Method area: JVM只有一个为所有的线程所共享的方法区.它存储类结构,例如运行时常量池,成员和方法数据以及方法.构造方法的代码. Java Stacks:每个JVM线程拥有一个私有的栈. Pc registers: JVM可以同时支持运行多个线程,因此每个线程需要各自的PC(program counter)寄存器. Native method stacks: 保存native方法进入区域的地址 .

JVM——新生代与老年代

首先看在JVM的堆中,按代的划分: Young:主要是用来存放新生的对象. Old:主要存放应用程序中生命周期长的内存对象. Permanent:是指内存的永久保存区域,主要存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域. 它和和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen s

JVM基础(5)-垃圾回收机制

一.对象引用的类型 Java 中的垃圾回收一般是在 Java 堆中进行,因为堆中几乎存放了 Java 中所有的对象实例.谈到 Java 堆中的垃圾回收,自然要谈到引用.在 JDK1.2 之前,Java 中的引用定义很很纯粹:如果 reference 类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用.但在 JDK1.2 之后,Java 对引用的概念进行了扩充,将其分为强引用(Strong Reference).软引用(Soft Reference).弱引用(Weak

高吞吐低延迟Java应用的垃圾回收优化

原文链接: linkedin 翻译: ImportNew.com- hejiani译文链接: http://www.importnew.com/11336.html 高性能应用构成了现代网络的支柱.LinkedIn有许多内部高吞吐量服务来满足每秒数千次的用户请求.要优化用户体验,低延迟地响应这些请求非常重要. 比如说,用户经常用到的一个功能是了解动态信息——不断更新的专业活动和内容的列表.动态信息在LinkedIn随处可见,包括公司页面,学校页面以及最重要的主页.基础动态信息数据平台为我们的经济