JVM学习日记1

今天是上班的第一个周日,记录一下最近学的JVM吧,很久没写博客了,写博客有助于激励自己,加油!
首先,先从开始说起吧。
以下全是个人不看书写出来的,个人的巩固记忆,需要官方的还请看《深入理解Java虚拟机》
JVM,Java Virtual Machine,顾名思义,Java的虚拟机,是Java程序运行的必要组件环境,JDK1.0后就提供了JVM的实现,JDK1.0的代表技术含括:JMV,Applet,AWT等。说到JDK,往往面试会问:JDK和JRE的区别,首先从全称来理解它们两个,JDK(Java Development Kit),直译就是Java的发展组件,也就是开发组件,实际上JDK是Java开发所需要的最小环境,而JRE(Java Runtime Environment),Java运行时的环境,可以看出来,JRE和JDK就是一个是运行的环境,一个是开发的组件,事实上,JDK包括了JRE,JRE加上java的开发工具以及各种API工具,就成为了JDK。之后的Java发展历史我记不太清楚了,比较重要的是1.7和1.8,JDK1.7后提供了G1收集器,泛型的简单推断,而1.8的就比较多了,有IO流的API提供,lambda表达式,对于HashMap的优化,方法区变成元空间等等。
JVM中,主要包含有方法区(非堆),堆,栈(本地方法栈,虚拟机栈),程序计数器。
程序计数器:主要是用来计算线程的指示器,对于当前线程的操作进行指示,比如说分支,循环还有跳转之类的,是线程私有的。
虚拟机栈:通常被称为“栈”,存放方法内存模型,也就是方法的局部变量都存放于虚拟机栈中,比如基本数据类型,对象的引用(注意不是对象的本身),在虚拟机栈中,出现的异常有栈溢出(SOF)和内存溢出(OOM)。线程的局部变量表,操作数栈,动态链接以及方法出口等信息都存放于此,虚拟机栈也是线程私有的。
本地方法栈:与虚拟机栈类似,不过本地方法栈使用的是Native方法,如果虚拟机栈中的Java方法(字节码)无法服务,就会用本地方法栈,主要是设定好的C/C++方法,本地方法栈也是线程私有的。
堆:堆是存放Java对象以及数组的内存区域,它又被称为GC堆,分为新生代和老年代,是所有线程都会共享的。
方法区:与堆做区别,被称为“非堆”,方法区也是被所有线程共享的内存区域,主要存储类信息,类常量以及各种的静态变量。它又被称为永久代,之所谓称为永久代,是因为在垃圾回收中,方法区的一般不会被回收,事实上并无永久代的概念。方法区中还有一个很重要的部分,叫运行时常量池,也就是平常所说的常量池,常量池有各种的常量数据(经典笔试面试题String还有int)。
导致OOM的原因:
1.Java堆中无法创建对象(一般是对象的引用长久存在无法被GC回收)
2.GC的开销过大,比如说95%的时间都在GC,却只恢复了5%的堆空间
3.栈申请的内存大小无法满足实际需求
4.内存不足无法新建线程
5.Metaspace(元空间)耗尽,1.7之前为永久代耗尽
6.数组过大,超过堆空间(很少见)
接下来是内存分配和垃圾回收。
内存分配上文已经讲了一部分,先讲垃圾回收。
在JVM中,经常使用到的垃圾回收器主要包含:
新生代:Serial,Parnew,Paraller Scavage
老年代:SerialOld,ParallerOld
其他重要两类:CMS,G1
Serial收集器是经典的单线程收集器,在1.7和1.7以前,JVM默认都是使用Serial收集器进行垃圾回收,而1.8之后,采用了双P收集器,也就是两个Paraller垃圾回收器。
ParallerScavage是一个优先吞吐量的垃圾回收器。在讲吞吐量之前,我们要认识到,GC也是要线程的,一般用户线程和GC线程会分隔进行,利用JVM书的例子就是你不能在你妈打扫卫生的时候同时丢垃圾。ParallerScavage会优先进行用户线程,也就是用户线程在所有线程时间的占比会高一些。
说到GC线程和用户线程,我总会先想到CMS(并发标记清除垃圾回收器),CMS是一个解决“你可以在你妈打扫卫生又同时丢垃圾”的垃圾回收器,它采用标记-清除的垃圾回收算法,分为四个步骤:
初始标记
并发标记
重新标记
并发清除
其中,初始标记和重新标记的时间很短,STW也就非常的短,因为并发标记时间长,且可以跟用户线程同时进行,所以CMS的并发性能特别好,吞吐量的比率也一般很高。
在1.7之后,推出了G1(Garbage First)收集器,它的意旨在于取代CMS的地位,其实步骤功能也跟CMS类似,分为:
初始标记
并发标记
最终标记
筛选回收
在G1中,提出了一个新的区概念,称为Region,无论是新生代还是老年代,都被分割成为一个一个的Region,采用了复制算法的思想,对于每一个Region进行清理回收,当一个Region里面没有引用的时候,这个Region就会被GC回收,想法其实很好,但实际上Region里面如果要检测是不是完全没有引用,实际上可能会全堆扫描,而不单单是新生代或者老年代,正因为出现这种可能,现在人们还是采用CMS而不是G1,G1的这种缺陷会让GC回收花销有可能变得很大。对于Region引用,保存引用的单位叫做Rset,每一个Region都会设有一个Rset,对于保存新生代的Region来说,它的Rset只会来自于老年代,因为新生代总是会被回收的,而对于老年代来说,它的Rset也只会来自于老年代,因为老年代回收之前,会先对新生代进行垃圾回收,所以没必要来自于新生代。
在新生代的GC时候,G1收集器只需要选定年轻代的RSet作为GC ROOTs,这些RSet记录了old->young的跨代引用,避免了扫描整个老年代。 而mixed gc的时候,老年代中记录了old->old的RSet,young->old的引用从Survivor区获取(老年代回收之前,会先对年轻代进行回收,存活的对象放在Survivor区),这样也不用扫描全部老年代,所以RSet的引入大大减少了GC的工作量。
怎么计算一个对象是否死亡?
有两种方式:
引用计数:每当一个对象引用增加,计数就加一,引用失效,计数就减一。
可达性分析:对对象进行GCroots引用分析,从GCroot作为根开始点进行往下探索分析,当分析到没有引用的时候,就认为无引用,启动finalize方法进行自我拯救。
垃圾回收算法:
1.复制
2.标记-清除
3.标记-整理
4.分代收集
内存管理分配:
1.大对象进入老年代
2.存活时间长的对象进入老年代
3.空间分配担保
4.动态对象年龄判断
5.优先分配在新生代

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值