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

来源:互联网 发布:新一代人工智能发展 编辑:程序博客网 时间:2024/06/06 04:38
程序计数器  本地方法栈  虚拟机方法区 这三个是随线程的消失而覆灭的, 随着方法的结束或线程的结束内存自然就会跟着被回收


java堆和方法区则不一样, 一个接口中的对个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样


不同的算法
一、引用计数算法 (这种算法是有问题的)
如果变量中有field指向的就是该对象本身, 则会产生该对象一直被假引用
二、可达性算法
通过一系列的称为GC Roots的对象作为起始点, 当一个对象到GC Roots没有任何引用链相连,就表明该对象是不可达的
作为GC Roots的对象包括下面几种:
1、虚拟机栈中引用的对象
2、方法区中类静态属性应用的对象
3、方法区中常量引用的对象
4、本地方法栈中JNI引用的对象


我们希望可以描述这样一类对象, 如果内存空间还足够时,则保留在内存中, 如果内存空间在进行垃圾回收之后还是很紧张的话, 则可以抛弃这样一些对象, 很多系统中的缓存对象都符合这样的应用场景


java中4类引用
1. 强引用  垃圾回收永远不会回收掉被引用的对象
2. 软引用  描述一些有用但是不是必须的对象, 如果第一次GC后内存还是很紧张, 则在第二次GC中才会清理这些对象, 如果第二次GC内存还是没有足够的空间, 才会抛出内存溢出异常
3. 弱引用  用来描述非必须的对象, 被弱引用的对象只能存活到下一次GC来临之前
4. 虚引用  这个是最弱的一种引用关系  为一个对象设置虚引用关联的唯一目的就是能让这个对象被收集器回收时受到一个系统的通知


finalize  (该方法的优先级较低)
如果一个对象是不可达的, 这个对象并非是facebook的,这个对象会进行一次筛选, 筛选的条件是此对象是否有必要执行finalize方法   当对象没有覆盖finalize方法(Object实现了该方法) 或者是虚拟机已经调用过该对象的finalize方法  虚拟机将这两种情况视为没必要执行
如果finalize拯救失败的话, 改对象就真的facebook了


回收方法区
永久代的垃圾收集主要回收两部分的内容 :废弃的常量和无用的类
常量只要满足无引用即可判定为废弃的常量
无用的类判断需要满足下面三个条件
1.该类的所有实例都已经被回收了 
2.加载该类的ClassLoader已经被回收了
3.该类的java.lang.Class对象没有在任何地方被引用
满足了这三个条件的还不一样被回收
如果大量使用反射,动态代理 CGLib等ByteCode框架,动态生成JSP已经OSGI这类频繁自定义ClassLoader的场景都需要虚拟机具有类卸载的功能, 保证永久代不会溢出






垃圾收集算法
一、 标记清除算法
该算法有两个问题   一个是效率问题, 标记和清除两个过程的效率都不会太高 另一个就是会产生大量不连续的内存碎片
二、复制算法
将内存分为两块, 每次只会使用其中的一块,将未标记的对象复制到另外一个未使用的内存中, 这种方法会牺牲掉一半的内存, 代价实在太高了
现代的商业虚拟机都采用这种算法来回收新生代,并不是按照1:1的比例来分配Eden和Survivor空间
三、标记整理算法
将所有存活的对象都想一端移动
四、分代收集算法
当前商业虚拟机的垃圾收集都采用“分代收集”,根据对象存活周期的不同将内存划分为几块, 一般是将其分为新生代和老年代


分析执行时间的敏感还体现在GC停顿上, 因为这个分析工作必须在一个能确保一致性的快照中进, 无论是什么收集器, 枚举跟节点时也是必须要停顿的


安全点:
在OopMap的协助下,HotSpot可以快速且准确完成GC的枚举
如果对每一条指令都生成对应的OopMap,那将会需要大量的额外空间, 虚拟机也没这样做, 而是设置了一些成为安全点的位置, 只有在到达安全点时才能暂停




在执行gc时, 所有的线程都跑到最近的安全点上停顿下来, 两种可供选择的方式
抢先式中断, 主动式中断


safepoint是针对正在执行的进程而言, 如果线程处于sleep或者block状态时,此时就要用到saftregion了, 在这个区域中的任意地方GC都是安全的


垃圾收集器
Serial收集器
此收集器是单线程的,单线程不仅仅说明他只会使用一个cpu或一个收集线程进行gc, 在gc过程中会停止掉其他的线程, Serial和Old Serial的口号是Stop the world
ParNew收集器
这个收集器和Serial有很多共同点, 在收集的时候使用多线程进行处理, 此收集器也是Stop The world


Parallel Scavenge收集器
该收集器关注的是达到一个可控制的吞吐量,而高吞吐量则可以高效率地利用cpu时间,尽快完成程序的运算程序


Serial Old收集器
该收集器是Serial的老年区版本, 也是采用的单线程的方式, 不过采用的收集算法是标记整理


Parallel Old收集器
该收集器是Parallel Scavenge的老年代版本


CMS收集器
是一种以获取最短回收停顿时间为目标的收集器
CMS是基于标记-清除算法实现的
CMS无法处理浮动垃圾,可能出现Concurrent Mode Failure失败而导致另一次Full Gc的出现
老年代区域需要预留空间给CMS的清理线程


G1收集器的运作大致可分为以下几个步骤
①初始标记
②并发标记
③最终标记
④筛选回收


理解GC日志


内存分配与回收策略
1.对象优先在Eden分配
动态对象年龄判定
如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半

















0 0
原创粉丝点击