赞
踩
其中的步骤是:当虚拟机碰到一条new指令时,先检查对象是否被加载,如果未被加载,就先将class加载到运行时数据区;然后虚拟机为对象分配内存,分配内存有两种方式:
内存空间如果不是碎片化的,内存中已经使用的和未使用的内存空间之间就有个指示器指针,分配内存就是挪动指示器的过程,这种方式称为指针碰撞(简单高效);
内存空间如果是碎片化的,虚拟机就会维护一张记录哪些空间是空闲可用的,分配内存的过程就是更新这张列表的过程,这种方式称之为空闲列表(复杂)。
分配内存的方式由垃圾回收器是否做内存整理来决定。
分配内存中需要考虑的重要一点就是并发安全,对象的创建时很频繁的,对内存空间的分配管理需要考虑并发安全的问题,解决这个问题有两个方案:
内存分配完,就是对内存空间进行初始化,这是一个赋零值的过程,之后虚拟机要对对象进行设置:
这样子,一个对象就产生了,虽然所有值都为“零”,但是咱们秃头将军们可以来“玩”她们了,咱们的new指令就可以根据构造方法来对他们进行初始化了。
对象创建出来之后,咱们就可以通过栈上的 reference 数据来操作堆上的具体对象了,访问一般有两种方式:句柄和直接指针
2.1 引用计数法: 在对象中添加一个引用计数器,每当有地方引用他就+1,引用失效就-1。但是遇到循环引用问题时需要引入额外的机制来处理,影响效率,python目前用的就是这种;
2.2 可达性分析算法: 以GCRoot为起点,开始往下搜索,这个过程中的路径成为引用链,当一个对象没有和引用链相连时,他就被判定是垃圾。
可作为GCRoot的对象(主要是前四种):
2.2.1. 虚拟机栈(栈帧中的本地变量表)中引用的对象;各个线程调用方法堆栈中使用到的参数、局部变量、临时变量等;
2.2.2. 方法区中类静态属性引用的对象;java 类的引用类型静态变量;
2.2.3. 方法区中常量引用的对象;比如:字符串常量池里的引用;
2.2.4. 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象;
2.2.5. JVM 的内部引用(class 对象、异常对象 NullPointException、OutofMemoryError,系统类加载器);
2.2.6. 所有被同步锁(synchronized 关键)持有的对象;
2.2.7. JVM 内部的 JMXBean、JVMTI 中注册的回调、本地代码缓存等;
2.2.8. JVM 实现中的“临时性”对象,跨代引用的对象。
在根可达算法判定为垃圾的对象,再经过一次标记筛选之后就会被GC回收,而在这之间,如果对这个对象执行了finalize()对他进行了一次"起死回生",GC就不会回收它,但是finalize()只能拯救它一次,也就说如果再将他指向空,再对他执行finalize(),它依旧会被GC回收。这个方法不可靠,不建议使用
6.1. 基本所有的对象都在堆上分配:这里说的是"基本",也就是说还有例外,例外就是在栈上分配,这种分配方式也称为逃逸。
6.2. 逃逸分析:调用参数传递到其他方法中,这种称之为方法逃逸,甚至还有可能被外部线程访问到,这种称之为线程逃逸
如果确定一个对象不会逃逸出线程之外,那么让对象在栈上分配内存可以提高 JVM 的效率。
6.3. 对象优先在 Eden 区分配
大多数情况下,对象在新生代 Eden 区中分配。当 Eden 区没有足够空间分配时,虚拟机将发起一次 Minor GC
6.4. 大对象直接进入老年代
大对象就是指需要大量连续内存空间的 Java 对象,他们会占用大量连续的内存空间,会导致提前触GC,而且在复制对象时会造成很大的内存开销。所以
HotSpot 虚拟机提供了-XX:PretenureSizeThreshold 参数,指定大于该设置值的对象直接在老年代分配,这样做的目的就是避免在 Eden 区及两个 Survivor 区之间来回复制,产生大量的内存复制操作。
6.5. 长期存活对象进入老年区
对象头中MarkWord记录了对象GC分代年龄,对象在eden区产生年龄为0,经过一次minorGC进入survivor区,年龄变成1,之后在survivor区每经过一次minorGC年龄就增加1,当到达一定年龄就进入老念代。并发垃圾回收器默认是15,CMS默认是6,参数-XX:MaxTenuringThreshold可以调整。
6.6. 对象年龄动态判定
虚拟机并不是一定要对象年龄到达一定大小才进入老年代,当survivor区所有相同年龄的对象大小总和大于survivor区一半时,年龄大于或等于该年龄的对象就直接进入老年代。
6.7. 空间分配担保
在发生minorGC之前,虚拟机会检查老年代连续可用空间是否大于新生代总空间大小,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次minorGC,尽管这次minorGC是有风险的,如果担保失败则会进行一次FullGC;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。