垃圾收集器与内存分配策略(六)之内存分配与回收策略

垃圾收集器与内存分配策略(六)——内存分配与回收策略

对象的内存分配,一般来说就是在堆上的分配(但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配),对象分配的细节取决于当前使用的是哪一种垃圾收集器组合,还有虚拟机中与内存相关的参数设置。

区分Minor GC与 Full GC:

新生代GC(Minor GC):指发生在新生代的的垃圾收集动作,因为Java对象大多具有朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。

老年代GC(Full GC / Major GC):老年代的GC,速度一般比Minor GC慢。

内存分配与回收策略

对象优先在Eden分配

大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够的空间进行内存分配时,虚拟机将发起一次Minor GC(新生代内存回收)。

虚拟机参数设置为-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8。其中-Xms20表示Java堆大小为20M; -Xmx20M与堆大小相等表示堆空间不可扩展; -Xmn10M表示其中10M分配给新生代(可推出老年代还剩下10M);-XX:SurvivorRatio=8表示当前Eden空间与survivor比例为8:1。

其中虚拟机通过参数 -XX:+PrintGCDetails打印垃圾收集器日志参数,告诉虚拟机在发生垃圾收集行为时打印内存回收日志。

大对象直接进入老年代

大对象是指需要大量连续内存空间的Java对象,如很长的字符串以及数组。

虚拟机提供参数-XX:PretenureSizeThreshold参数来指定大对象,大于该值的对象都是大对象直接在老年代分配,避免在Eden和二个survivor之间发生大量内存复制。

编程时应尽量避免“朝生夕死”的大对象。

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

内存回收时要求能识别哪些对象应放在新生代,哪些对象应放在老年代。虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活且能被Survivor容纳的话,将被移动到Survivor空间,并且对象年龄设为1,对象在Survivor区中每经过一次Minor GC,年龄就增加1岁,当年龄增加到一定程度(默认是15岁),就会晋升到老年代。

对象晋升到老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。

动态对象年龄判定

虚拟机并不是永远地要求对象的年龄必须达到MaxTenuringThreshold才能晋升到老年代,如果Survivor空间中相同年龄对象大小的总和大于Survivor空间的一半,年龄大于等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。

空间分配担保

在发生Minor GC之前,虚拟机会先检查老年代最大可用连续空间是否大于新生代所有对象占用的内存总空间,

  如果条件成立,那么Minor GC可以确保是安全的。

  如果不成立,虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。

    如果允许那么会继续检查老年代最大可用连续内存空间是否大于历次晋升到老年代对象的平均大小,

      如果大于,将尝试进行一次Minor GC,但本次Minor GC存在风险;

      如果小于或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC,让老年代腾出更多的空间。

但是在JDK6 Update24之后,HandlePromotionFailure参数将不会影响到虚拟机的空间分配担保策略,观察OpenJDK中的源码可以发现虽然还定义了该参数,但是代码中已不使用它了。JDK6 Update24之后的规则变为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。

时间: 2024-12-23 08:02:07

垃圾收集器与内存分配策略(六)之内存分配与回收策略的相关文章

JVM(3) 垃圾收集器与内存分配策略

一.垃圾收集的概念 在Java虚拟机运行时数据区中程序计数器.虚拟机栈和本地方法栈3个区域随线程而生,随线程而灭:栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作,每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的,因此这几个区域的内存分配和回收都具备确定性,因为方法结束或线程结束时,内存自然就跟随着回收了. 而Java堆和方法区则不一样,一个接口的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,只有在程序处于运行期间时才能知道会创建哪些对象,这

深入理解JVM读书笔记二: 垃圾收集器与内存分配策略

3.2对象已死吗? 3.2.1 引用计数法 给对象添加一个引用计数器,每当有一个地方引用它的地方,计数器值+1:当引用失效,计数器值就减1;任何时候计数器为0,对象就不可能再被引用了. 它很难解决对象之间相互循环引用的问题. 3.2.2 可达性分析算法 这个算法的基本思路就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC

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

1.概述 程序计数器.虚拟机栈.本地方法栈是线程私有的,内存分配和回收都具有确定性,不需要考虑垃圾回收的问题,方法结束或者线程结束,内存就自然回收了 java堆和方法区的内存的分配和回收都是动态的,垃圾收集器所关注的是这部分的内存 2.垃圾收集器处理的对象 垃圾收集器需要确定哪些对象还"存活"着,哪些已经"死去"(不可能再被任何途径使用的对象) ①引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻

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

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

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

引言 垃圾收集技术并不是Java语言首创的,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.垃圾收集技术需要考虑的三个问题是: 哪些内存需要回收 什么时候回收 如何回收 http://my.oschina.net/jiangmitiao/blog/470426 中讲到java内存运行时区域的分布,其中程序计数器,虚拟机栈,本地方法区都是随着线程而生,随线程而灭,所以这几个区域就不需要过多考虑回收问题.但是堆和方法区就不一样了,只有在程序运行期间我们才知道会创建哪

垃圾收集器与内存分配策略(深入理解Java虚拟机)

3.1 概述 垃圾收集器要解决哪些问题? 哪些内存需要回收 什么时候回收 如何回收 引用计数算法:当有一个地方引用,+1,引用失效,-1.     缺点:对象之间相互循环引用的问题. 可达性分析算法: 思路:通过一系列的成为"Gc Roots"的对象作为起始点,从这些节点开始向下探索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到Gc Roots没有任何引用链相连,则则很难革命此对象是不可用的. Java语言中GC Roots的对象包括下面几种: 1.虚拟机

java虚拟机之垃圾收集器与内存分配策略

哪些内存需要回收? java内存运行时区域的各个部分,其中程序计数器,虚拟机栈,本地方法栈3个区域随线程而生,随线程而灭,栈中的栈帧随着方法的进入和退出而有条不絮的执行着出栈和入栈操作.每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的.因此这几个区域的内存分配和回收都具有确定性,所以这部分不需要过多考虑内存回收.但是方法区和堆不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分的分配和回收都

【深入理解JAVA虚拟机】第二部分.内存自动管理机制.3.垃圾收集器与内存分配策略

1.学习目的 当需要排查各种内存溢出. 内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节. Java内存运行时区域的各个部分,其中程序计数器. 虚拟机栈. 本地方法栈3个区域随线程而生,随线程而灭:栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作. 因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了. 而Java堆和方法区则不一样,一个

垃圾收集器与内存分配策略(1)

1.概述 Java内存运行时区域,其中程序计数器.虚拟机栈.本地方法栈三个区域随线程而生,随线程而灭:栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作.每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的,因此在这几个区域的内存分配和回收都具备确定性.而Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能也不一样,一个方法中的多个分支需要的内存也可能不一样,这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分内存. 2.对象生死 堆中几乎存放着Java世界