JVM笔记-自动内存管理机制(一)

1.运行时数据区域

程序计数器:改变该值来选取下一条执行的字节码指令

这是此内存趋于唯一一个不会OutOfMemoryError的区域

虚拟机栈:用于存储局部变量表、操作数栈、动态链接、方法出口等信息

本地方法栈:存储Native方法

:存放对象实例,也是垃圾回收的主要区域

方法区:也称为老年代,存储已加载的类信息、常量、静态变量等。

该区域GC可实现也可不实现,GC效率低

 

对象的访问定位

通过栈上的reference来操作堆上的具体对象

有两种主流的访问方式:①使用句柄②直接指针

各自优势:

句柄访问:reference存储稳定的句柄地址,在对象被移动后只会修改句柄中的指针,

reference本身不需要修改

直接指针:速度快,少一次指针定位的时间

 

OutOfMemoryError异常

java堆溢出

内存泄漏,通过工具查看泄漏对象到GC Roots的引用链,就可以找到泄漏位置。

内存溢出,对象都存活着,查看堆参数是否能调大,或者对象生命周期过长或者持有时间过长

虚拟机栈和本地方法栈溢出

在单线程的情况下抛出都是StackOverflowError异常,多线程才可能会OutOfMemoryError

每个线程分配到的栈容量越大,建立线程越容易把剩下的内存耗尽

因为建立过多线程导致内存溢出,可以减少最大堆和减少栈容量来换取更多线程

方法区和运行时常量池溢出

当spring、hibernate对类增强时,需要大的方法区保证生成class能载入内存

本机直接内存溢出

如果OOM后Dump文件很小,而程序中直接或间接使用了NIO就有可能是这个问题

 

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

判断对象存活还是死亡

引用计数算法,给对象添加一个引用计数器,每有一个地方引用计数器就+1,

引用失效计数器就-1,到0的时候就可以判定死亡

缺点:很难解决对象之间的循环引用

可达性分析算法,一系列称为“GC Roots”对象作为起始点,作引用链遍历,

当一个对象到GC Roots没有任何引用链,则判断死亡

哪些对象可称为GC Roots:

虚拟机栈中引用的对象,方法区中静态属性引用的对象,方法区中常量引用的对象

 

垃圾收集算法

标记清除法,先标记需回收对象,然后统一进行回收。

不足:标记和清除两个过程效率不高,清除后产生大量不连续的内存碎片

复制算法,将内存划分大小相等两块,每次只使用一块,用完了,把活着的复制到另一块上,

清空当前这块。不用担心内存碎片。适合新生代

不足:浪费一半的内存。

标记整理,让存活的对象向一端移动,清理掉端边界外的内存,适合于老年代。

分代收集,把堆分为老年代和新生代,采用不同的收集算法。

 

HotSpot算法实现

枚举根节点,从GC Roots的引用中查找非常耗时,而且需要stop world来确保一致性

OopMap使得可直接得到引用地址,省时。

安全点,只有在安全点才会记录OopMap,所以在安全点才会GC。

是否具有让程序长时间执行的特征是选择安全点的依据。

两种方案使所有线程在最近的安全点上停顿:

       抢先式中断,发生GC时,先全部中断,如果有线程没在安全点上,就恢复使其跑到安全点。不适用。

       主动式中断,发生GC时,设置一个标志,所有线程主动轮询这个标志,为真时中断挂起。

安全区域,是安全点的扩展,在一段代码中引用关系不会变化,在这个区域GC是安全的。

 

垃圾收集器

Serial收集器,只使用一个线程去收集垃圾,每次收集都要stop world。

单线程情况下,简单高效,没有线程交互开销,适合新生代

ParNew收集器,serial的多线程版,配合CMS使用,在线程少的情况下,效率还不如serial

Parallel Scavenge收集器,为了达到一个可控的吞吐量,和ParNew类似的多线程收集器

GC停顿缩短是以牺牲吞吐量和新生代空间来换取的,如果把新生代内存调小,停顿时间确实下降,但吞吐量也下降了。

相同时间内停顿的次数多了,每次停顿时间少了,利于用户交互,但停顿造成的总时间变大了

Serial Old收集器,serial的老年代版本,

 

Parallel Old收集器,在注重吞吐量以及CPU敏感的场合可以考虑Parallel Scavenge和Parallel Old

CMS收集器(重要),使得停顿时间最短,基于标记清除

①初始标记,stop world,标记GC Roots能直接关联到的对象

②并发标记,GC RootsTracing,与用户线程一起工作

③重新标记,stop world,修正并发标记期间用户线程继续运作导致标记变动的对象标记

④并发清除,与用户线程一起工作

缺点:对CPU资源敏感,在并发阶段占用一部分CPU资源,总吞吐量降低。

无法处理浮动垃圾,清理阶段和用户线程并发,还会有垃圾产生,只能在下次GC清理这些垃圾。

 

G1收集器(重要),追求低停顿,

①初始标记,stop world,标记GC Roots能直接关联到的对象,修改TAMS值,使得下一阶段能在正确的Region创建对象

②并发标记,GC Roots可达性分析,找出存活对象

③最终标记,stop world,修正并发标记时程序运行导致标记的改变

④筛选回收,对各个Region的回收价值和成本进行排序,根据用户期望GC停顿时间来制定回收计划

 

内存分配与回收策略

对象优先在新生代Eden区分配,如果没有足够空间则会进行一次Minor GC(新生代GC)

大对象直接进入老年代

长期存活的对象将进入老年代,给对象添加一个age计数器,每过一个Minor GC,年龄+1,到一定程度晋升到老年代

动态对象年龄判定,如果Survivor空间相同年龄对象总和大于Survivor空间的一半,那么大于或等于这个年龄的对象,

可以直接进入老年代。

空间分配担保,Minor GC前检查老年代最大可用连续空间是否大于新生代所有对象总空间,如果可以,则可保证GC安全

否则,查看配置HandlePromotionFailure决定是否冒险,如果老年代连续空间大于历次晋升到老年代对象的平均大小,则冒险,

否则进行一次Full GC。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值