JVM-新生代和老年代

新生代分为三个区域,一个Eden区和两个Survivor区,它们之间的比例为(8:1:1),这个比例也是可以修改的。通常情况下,对象主要分配在新生代的Eden区上,少数情况下也可能会直接分配在老年代中。Java虚拟机每次使用新生代中的Eden和其中一块Survivor(From),在经过一次Minor GC后,将Eden和Survivor中还存活的对象一次性地复制到另一块Survivor空间上(这里使用的复制算法进行GC),最后清理掉Eden和刚才用过的Survivor(From)空间。将此时在Survivor空间存活下来的对象的年龄设置为1,以后这些对象每在Survivor区熬过一次GC,它们的年龄就加1,当对象年龄达到某个年龄(默认值为15)时,就会把它们移到老年代中。

在新生代中进行GC时,有可能遇到另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象,这些对象将直接通过分配担保机制进入老年代;

1.Eden区

Eden区位于Java堆的年轻代,是新对象分配内存的地方,由于堆是所有线程共享的,因此在堆上分配内存需要加锁。而Sun JDK为提升效率,会为每个新建的线程在Eden上分配一块独立的空间由该线程独享,这块空间称为TLAB(Thread Local Allocation Buffer)。在TLAB上分配内存不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配。如果对象过大或TLAB用完,则仍然在堆上进行分配。如果Eden区内存也用完了,则会进行一次Minor GC(young GC)。

2.Survival from to

Survival区与Eden区相同都在Java堆的年轻代。Survival区有两块,一块称为from区,另一块为to区,这两个区是相对的,在发生一次Minor GC后,from区就会和to区互换。在发生Minor GC时,Eden区和Survivalfrom区会把一些仍然存活的对象复制进Survival to区,并清除内存。Survival to区会把一些存活得足够旧的对象移至年老代。

3.年老代

年老代里存放的都是存活时间较久的,大小较大的对象,因此年老代使用标记整理算法。当年老代容量满的时候,会触发一次Major GC(full GC),回收年老代和年轻代中不再被使用的对象资源。

总结:

1、Minor GC是发生在新生代中的垃圾收集,采用的复制算法;

2、新生代中每次使用的空间不超过90%,主要用来存放新生的对象;

3、Minor GC每次收集后Eden区和一块Survivor区都被清空;

4、老年代中使用Full GC,采用的标记-清除算法

注意:

堆=新生代+老年代,不包括永久代(方法区)。

很多人认为方法区(或者HotSpot虚拟机中的永久代)是没有垃圾收集的,Java虚拟机规范中确实说过可以不要求虚拟机在方法区实现垃圾收集,而且在方法区进行垃圾收集的“性价比”一般比较低:在堆中,尤其是在新生代中,常规应用进行一次垃圾收集一般可以回收70%~95%的空间,而永久代的垃圾收集效率远低于此。

永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。回收废弃常量与回收Java堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串“abc”已经进入了常量池中,但是当前系统没有任何一个String对象是叫做“abc”的,换句话说是没有任何String对象引用常量池中的“abc”常量,也没有其他地方引用了这个字面量,如果在这时候发生内存回收,而且必要的话,这个“abc”常量就会被系统“请”出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是“无用的类”:

该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。

加载该类的ClassLoader已经被回收。

该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可以对满足上述3个条件的无用类进行回收,这里说的仅仅是“可以”,而不是和对象一样,不使用了就必然会回收。是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class及-XX:+TraceClassLoading、 -XX:+TraceClassUnLoading查看类的加载和卸载信息。

在大量使用反射、动态代理、CGLib等bytecode框架的场景,以及动态生成JSP和OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。

原文地址:https://www.cnblogs.com/jingpeng77/p/12404869.html

时间: 2024-11-10 17:29:40

JVM-新生代和老年代的相关文章

JVM——新生代与老年代

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

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过程中的幸存者.

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

新生代和老年代 对象在被实例化之后,都是属于新生代. 大部分新生代的生命周期都是及其短暂的,例如在一个方法中创建的对象会随着方法执行完毕,栈空间的栈帧出栈后而失去引用. 而有一些对象确实会长期存活在堆内存的,比如被Static引用的对象.这种对象不会轻易的被垃圾回收器回收. 所以JVM会将堆内存分为两个区域,一个年轻代,一个老年代. 其中年轻代,顾名思义,就是创建和使用完之后立马就要被回收的对象放在里面.然后老年带呢,就是把一些会长期存活的对象放在里面. 为什么要分成新生代和老年代 很多人都会有

堆中的新生代与老年代

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

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

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

JVM 年轻代 老年代 持久代 gc

虚拟机中的共划分为三个代:年轻代(Young Generation).老年代(Old Generation)和持久代(Permanent Generation).其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大.年轻代和年老代的划分是对垃圾收集影响比较大的. 年轻代: 所有新生成的对象首先都是放在年轻代的.年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象.年轻代分三个区.一个Eden区,两个Survivor区(一般而言).大部分对象在Eden区中生成.当Ed

JVM 晋升到老年代的动态年龄判断

虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄. 这个表述应该是老的虚拟机的动态年龄判断算法,其实推演一下是存在缺陷的的,请看下图: 如果此时又有15%的对象要进入Survivor区,此时存活的对象超过Survivor的大小,要全部进入老年代,其实这样不

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

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方法进入区域的地址 .