JVM 中的对象及引用
JVM 中对象的创建过程
对象的内存分配
虚拟机遇到一条 new 指令时,首先检查是否被类加载器加载,如果没有,那必须先执行相应的类加载过程。类加载就是把 class 加载到 JVM 的运行时数据区的过程
分配内存
指针碰撞
如果 Java 堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅
是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”。Serial、ParNew
空闲列表
如果 Java 堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上
哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”。CMS
在 HotSpot 虚拟机中,对象在内存中存储的布局可以分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)
判断对象的存活
可达性分析
来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是不可用的。
虚拟机栈(栈帧中的本地变量表)中引用的对象;各个现场被调用方法堆栈中使用到的参数、局部变量、临时变量等。
方法区中类静态属性引用的对象;java 类的引用类型静态变量。
方法区中常量引用的对象;比如:字符串常量池里的引用。
本地方法栈中 JNI(即一般说的 Native 方法)引用的对象。
对象的分配策略
堆和栈上分配(逃逸分析)
进入老年代的几种方式
-
躲过15次GC之后进入老年代
-
当前放对象的Survivor区域里一批对象的总大小大于了这块Survivor区域的内存大小的50%,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代
-
大对象直接进入老年代
-
老年代空间分配担保,有可能触发FullGc