垃圾收集器与内存分配策略-内存分配与回收策略

如何去给对象分配内存?大方向讲,就是在堆上分配(但也可能经过JIT编译后被拆散为标量类型并间接地在栈上分配)

①对象优先在Eden分配

大多数条件下,对象在Eden中分配,当Eden内存不够的时候,虚拟机将发起一次Minor GC。

private static final int  _1MB=1024*1024;
/**
 * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M (限制了java堆大小为20MB,新生代10MB,老年代10MB)-XX:+PrintGCDetails(虚拟机发生GC时会收集日志) -XX:SurvivorRatio=8(规定Eden与Survivor比例为8/1)
 */

  public static void test{
   byte[]  allocation1,allocation2,allocation3,allocation4;
   allocation1=new byte[2*_1MB];
   allocation2=new byte[2*_1MB];
   allocation3=new byte[2*_1MB];
   allocation4=new byte[4*_1MB];//出现一次Minor GC

}

 java堆占10MB,Eden占8MB,创建前三个对象在Eden中占了6MB,当创建第四个对象时,第四个对象4MB,Eden区无法分配足够内存,所以发生一次GC,虚拟机又发现前三个对象无法放到Suvivor空间中,因为一个Suvivor空间只有1MB,所以通过分配担保机制直接到老年代去。

② 大对象直接进入老年代

大对象是指需要大量连续内存空间的Java对象(比如很长的字符串和数组)。经常出现大对象就会提前触发GC以获取连续的空间来放置他们。

/**
 *
 *VM参数:-verbose:gc  -Xms20M  -Xmx20M  -Xmn10M
 *-XX:+PrintGCDetails -XX:SurvivorRatio=8
 *-XX:PretenureSizeThreshold=2145728(令大于这个值得对象直接在老年代中分配,只对Serial和ParNew两款收集器有效)
 */
public class aaa {
private static final int _1MB=1024*1024;
public static void main(String[] args){
	byte[] allocation;
	allocation=new byte[4*_1MB];
}
}

  

③长期存活的对象将进入老年代

为了实现分代手机的思想,内存回收时就应该能识别哪些对象应放在新生代,哪些对象应放在老年代。为了达到这个目的,虚拟机给每个对象定义了一个对象年龄计数器。


当对象在Eden出生并经过第一次存活并能移动到Surivor中,将年龄设为1,在Surivor中每经过一次GC,年龄加1,等到了默认年龄15岁(可以通过-XX:MaxTenuringThreshold方法改变这个值),就会被移动到老年代。

④ 动态对象年龄判定

为了适应不同程序得内存状况,虚拟机不是永远要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄的所有对象大小的总和大于Survior空间的一半,年龄大于或等于该对象就可以直接进入老年代

⑥ 空间分配担保


在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么Minor GC可以保证是安全的。如果不成立,虚拟机会查看HandlePromotionFailure设置值是否允许担保失败,如果允许,那么就继续检查,看看老年代最大的连续可用空间是不是比历次新生代往老年代传的平均值大,如果大于,将会尝试一次Mionr GC,但是这是有风险的,如果小于,或者HandlePromotionFailure设置不允许冒险,就会改为进行一次Full GC。

如果不管HandlePromotionFailure的阻拦,非要进行Minor GC,到底会冒什么风险呢?

复制算法时提到,为了内存利用率,只是用其中一个Survior进行轮换备份,因此当出现大量对象在Minor GC后仍然存活的情况,就需要老年代进行分配担保,把Survivor无法容纳的对象直接进入老年代,老年代要进行这样的担保,前提是老年代本身还有容纳这些对象的剩余空间,一共有多少对象会活下来在实际完成回收之前是没有办法确定的所以只好取之前每一次回收晋升到老年代对象的平均值大小作为依据,与老年代剩余空间进行比较,决定是否Full GC来让老年代腾出更多空间。

取平均值进行比较仍然是一种动态概率手段,总会出现某一次突然比平均值大很多的情况,所以依然会导致担保失败,如果出现了担保失败,那么就只好重新发起一次Full GC,虽然担保失败时绕的圈子是最大的,但大部分情况下还是会将HandlePromotionFailure开关打开,避免Full GC太过于频繁。

时间: 2024-08-01 10:50:32

垃圾收集器与内存分配策略-内存分配与回收策略的相关文章

深入理解JAVA虚拟机 垃圾收集器和内存分配策略

引用计数算法 很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器都为0的对象就是不可能再被使用的. 客观地说,引用计数算法(Reference Counting)的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软的COM(Component Object Model)技术.使用ActionScript 3的FlashPlayer.Python语

垃圾收集器与内存分配策略之篇二:垃圾收集器

五.垃圾收集器 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现.由于java虚拟机规范对垃圾收集器实现没有任何的规范因此不同的厂商,不同的版本的虚拟机所提供的垃圾收集器都有可能会有很大的区别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器. 虚拟机中所包含的垃圾收集器如下图: 连线代代表他们可以组合使用.下面分别对以上垃圾收集器进行说明: 01)Serial 是历史悠久的收集器,在垃圾回收期间或中断用户线程,是一个单线程的收集器,在进行垃圾

深入理解JVM:垃圾收集器与内存分配策略

堆里面存放着Java世界几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还存活,哪些已经死去.判断对象的生命周期是否结束有以下几种方法 引用计数法 具体操作是给对象添加一个引用计数器,每当有一个地方引用时,计数器的值就加1,:当引用失效时,计数器就减1:任何时刻计数器为0的对象就 是不可能再被使用的.客观的说引用计数器算法实现简单,判定效率也很高,在大部分情况下他都是一个不错的算法.但是引用计数器有缺陷 举个简单的例子,对象A和对象B都有字段instance,

垃圾收集器

垃圾收集器 引用计数器: 从gc日志可以看出是回收了,java虚假没有选用引用计数器算法管理内存 可达性分析算法 ?线程池中线程是维持一个数量还是,用已经有的线程? 回收方法区 垃圾收集器 垃圾收集器根据应用场景和内存回收范围来选择.根据新生代.老年代,高性能服务器.客户端,计算密集场景.高响应场景.选择不同的收集器. 单线程收集器 单线程收集器,是使用单线程去完成垃圾回收工作.在垃圾收集的同时要暂停其它所有的工作线程,直到收集结束.即"Stop The World". 多线程收集器

GC算法 垃圾收集器

GC算法 垃圾收集器 参考:http://www.cnblogs.com/ityouknow/p/5614961.html 概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 java 堆和方法区中,在程序运行期间,这部分

G1 垃圾收集器

概念先知 什么是垃圾回收 简单的说垃圾回收就是回收内存中不再使用的对象. 垃圾回收的基本步骤: 查找内存中不再使用的对象 释放这些对象占用的内存 查找内存中不再使用的对象 如何判断哪些对象不再被使用呢?有2个方法: 引用计数法 引用计数法就是如果一个对象没有被任何引用指向,则可视之为垃圾.这种方法的缺点就是不能检测到环的存在. 根搜索算法 根搜索算法的基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference

深入理解 Java G1 垃圾收集器--转

原文地址:http://blog.jobbole.com/109170/?utm_source=hao.jobbole.com&utm_medium=relatedArticle 本文首先简单介绍了垃圾收集的常见方式,然后再分析了G1收集器的收集原理,相比其他垃圾收集器的优势,最后给出了一些调优实践. 一,什么是垃圾回收 首先,在了解G1之前,我们需要清楚的知道,垃圾回收是什么?简单的说垃圾回收就是回收内存中不再使用的对象. 垃圾回收的基本步骤 回收的步骤有2步: 查找内存中不再使用的对象 释放

【006】【JVM——垃圾收集器总结】

 JVM--垃圾收集器总结 垃圾收集器概览 收集算法是内存回收的方法论,垃圾收集据是内存回收的具体实现.Java虚拟机规范中对垃圾收集器应该如何实现没有规定,不同的厂商.不同版本的虚拟机所提供的垃圾收集器可能会有很大差别,一般都会提供参数供用户根据自己的所用特点和要求组合出各个年代所使用的收集器.下面是基于JDK 1.7 Update 14 之后的HotSpot 虚拟机垃圾收集器.如果两个收集器之间有连线就说明它们可以搭配使用.直到现在还没有最好的收集器,更加设有万能的收集器,只是对具体应用

java GC算法 垃圾收集器

GC算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此,我们的内存垃圾回收主要集中于 java 堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的. 对象存活判断 判断对象是否存活一般有两种方式: 引用计数:每个

GC原理---垃圾收集器

垃圾收集器 如果说收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现 Serial收集器 串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收.新生代.老年代使用串行回收:新生代复制算法.老年代标记-压缩:垃圾收集的过程中会Stop The World(服务暂停) 参数控制:-XX:+UseSerialGC 串行收集器 ParNew收集器 ParNew收集器其实就是Serial收集器的多线程版本.新生代并行,老年代串行:新生代复制算法.老年代标记-压