深入理解Java虚拟机---学习感悟以及笔记
一、为什么要学习Java虚拟机?
这里我们使用举例来说明为什么要学习Java虚拟机,其实这个问题就和为什么要学习数据结构和算法是一个道理,工欲善其事,必先利其器。曾经的我经常害怕处理内存溢出的问题,因为不知道他为什么会出现这个问题,当我在看了这本书以后明白了垃圾回收算法,以及JVM是如何帮助我们处理GC的,这个时候当出现这个问题的时候我就明白需要查找GC Root,或者查看GC日志,去查找这个问题的根源,这样就能处理这些问题。还有以前的在理解重载和重构的时候只是在表面去理解,当我看完这本书明白,原来在方法调用时候这些东西就生成处理,另外还有一个new到底经历那些事情等等一序列问题,如果你还在就纠结一些问题为什么是这么处理的时候那你就去看Java虚拟机吧,或许会有不一样的感悟,以上就是为什么要学习Java虚拟机的原因,可能有部分解释的不是很全面,我想在感悟方面在仔细说一下这个问题。
二、感悟?
其实也算不上什么感悟,只是对一些问题认识更加深刻而已,这里面我们来谈一下GC,要探讨这个问题我们需要从4个方面入手:
1.JVM是如何分配内存的?
2.如何才能保证正确的回收?
3.JVM什么情况下触发GC以及GC的方式?
4.如何监控和优化GC?
首先从JVM内存分布开始:下图是JVM内存分布图
1.线程计数器,是一块较小的内存空间,用来指定当前线程执行字节码的行数,每个线程计数器都是私有的,因为每个线程都需要记录执行的行数;这里解释一下为什么每个线程都需要一个线程计数器,JVM的多线程是通过线程轮流切换分配执行时间来实现的,在任何时刻,每个处理器都只会执行一个线程中的指令,当线程进行切换的时,为了线程能恢复当正确的位置,所以每个线程必须有个独立的线程计数器,这样才能保证线程之间不互相影响。
这里注意下,如果线程执行是一个Java方法的时候,计数器记录的是虚拟机字节码指令的地址;当执行的是Native的方法的时候,计数器指令为空;该内存区域是Java虚拟机唯一没有规定任何OutOfMemoryError的区域。
2.Java虚拟栈,这个也是一个线程私有的,生命周期与线程是同步的,每个方法在执行的同时,都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出入口等信息,每个方法的调用到执行完成的过程就是一个栈帧入栈到出栈的过程;
这里解释一下局部变量表,局部变量表存储方法相关的局部变量,包括基本数据,对象引用和返回地址等。在局部变量表中,只有long和double类型会占用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),其它都是1个Slot。需要注意的是,局部变量表是在编译时就已经确定好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变。这部分东西我还想等下一篇博客的时候我想仔细说一下字节码的执行过程;
虚拟机栈规定了2种异常情况,一种是线程请求栈的深度大于虚拟机栈所允许的深度,这时候将会抛出StackOverflowError异常,如果当Java虚拟机允许动态扩展虚拟机栈的时候,当扩展的时候没办法分配到内存的时候就会报OutOfMemoryError异常;
3.本地方法栈,与虚拟机栈执行的基本相同,唯一的区别就是虚拟机栈是执行Java方法的,本地方法栈是执行native方法的;
4.Java堆,堆区是Java虚拟机所管理的内存中最大的一块,Java堆是被所有线程共享的内存区域,主要存储对象的实例。
当堆中没有内存完成实例分配,并且堆无法扩展的时候,将会抛出OutOfMemoryError异常;当前虚拟机都是可以扩展的;
5.方法区,这个也是线程共享的内存区域,存储被虚拟机加载的类信息、常量、静态变量、即时编译的代码数据等;
方法区在物理上也是不需要连续的,可以选择固定大小或者扩展的大小,还可以选择不实现垃圾收集,方法区的垃圾回收是比较少的,这就是方法区为什么被称为永久区的原因,但是方法区也是可以执行回收的,该区域主要是针对常量池和类型的卸载;在方法区也规定当方法区无法满足内存分布的时候,将会抛出OutOfMemoryError异常;
运行时常量是方法区的一部分,常量池主要用于存放编译生成的各种字面量和符合引用,由于常量池属于方法区的一部分,所以当常量池没有内存空间的时候就抛出OutOfMemoryError异常;
6.直接内存,不是虚拟机运行时的一部分,可以直接访问堆外的内存;所以当内存空间无法动态扩展的时候就会出现OutOfMemoryError异常;
以上基本是JVM内存分布的内容,简单的理解水满则溢出就是这个道理,系统的整个空间是一个大的容器,分不同的部分或者桶去分担整个容量,当那个桶不够的时候自然会溢出。明白内存区域的分布我们看下对象是如何分配在内存空间里面的?
Java对象这里指的是引用类型的对象,这里用Student stu=new Student()为例子访问,Student stu作为引用对象,存在与Java虚拟机栈上,new Student()保存在Java堆中,堆中记录Student类型的信息包括方法,接口,对象类型等地址,这些类型的执行的数据存储在方法区中;
这里需要说明一下对象访问的方式,主要包括2种句柄访问和直接指针访问:
1. 句柄访问主要是Java堆中划分一块句柄池,虚拟机栈中存放句柄池中的地址,句柄池中包括对象的实例数据和对象类型的数据的地址,基本分布如下图:
2.直接指针访问,就是虚拟机栈直接指向Java堆中的对象类型指针和对象的实例数据,然后对象类型指针在指向方法区中对象类型的实例数据,分布如下图:
HotSpot就是第二种访问方式,优点在于访问速度快,省去一次指针开销时间,JVM内存分布基本介绍到这里,接下来说下如何保证正确回收?
回收是已经没有用的对象,那怎么判断一个对象没用引用?这里需要简单介绍2种方法:引用计数法和可达性分析算法;
这里简单说一下引用计数法:对象中添加一个引用计数器,每当有一个地方引用计数器就增加1,引用失效就减少1,计数器为0就不可用;缺点就在于无法处理对象直接相互引用的问题,因为相互引用以后无法使计数器为0,所以无法回收;
可达性分析算法,也就是我们常说的GC Root,,当一个对象没有与任何引用链相连的时候,就可以对该对象进行回收,下面是Java中GC Root对象使用的几个地方:
以上对象简单就是分为可用和不可用这2种,现在Java对引用概念进行扩充:
明白这些我们基本明白JVM如何正确回收,接下来就是JVM什么情况下触发GC以及GC触发的方式?
第一个问题比较容易回答当然是当内存空间不足的时候就需要触发GC,GC回收的时候采用的是分代收集的算法,主要分为年轻代和老年代,接下来我们简单介绍一下这2种方式:
年轻代:当一个对象被创建的时候,内存分配首先分配在年轻代,大部分对象创建以后都不再使用,对象很快变得不可达,就是对象无用,由于垃圾是被年轻代清理掉的,所以被叫做Minor GC或者Young GC。
老年代:对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代大,能存放更多的对象,在年老代上发生的GC次数也比年轻代少。当年老代内存不足时,将执行Major GC,也叫 Full GC。
明白这2块主要存放什么东西以后接下来我们看下GC的整体结构,看一个对象如何被Kill掉的流程:
1.当一个对象被创建的时候(new)首先会在年轻代的Eden区被创建,直到当GC的时候,根据可达性算法,看一个对象是否消亡,没有消亡的对象会被放入年轻带的Survivor区,消亡的直接被Minor GC Kill掉;
2.进入到Survivor区的对象也不是安全的,当下一次Minor GC来的时候还是会检查Enden和Survivor存放对象区域中对象是否存活,存活放入另外一块Survivor区域;
3.当2个Survivor区切换几次以后,会直接进入老年代,当然进入到老年代也不是安全的,当老年代内存空间不足的时候,会触发Major GC,已经消亡的依然还是被Kill掉;
推荐一个这个写的很逗可以看下:http://blog.csdn.net/sd4015700/article/details/50109939
接下来我们还需要说一下GC的算法:标记--清除,复制,标记--整理这3种算法;
了解算法和GC内存分布以后我们接下来介绍垃圾回收器,这部分内容我不计划用文字去介绍,在第三个栏目我会将我对《深入理解Java虚拟机》这本书的思维导图,内容还不是很完善我正在整理中,但是有GC这部分内容包括各种参数配置,大家可以下载下来具体了解一下;
最后我们谈一下监控和优化,当年具备以上知识以后这些都将不是问题,所以工欲善其事必先利其器,这就是我要说的,剩下就是对工具操作,这些我认为不需要介绍也是可以的,当然我也推荐一个博客:http://blog.csdn.net/renfufei/article/details/56678064
三、结束语
思维导图工具:XMind
百度云盘地址:链接:https://pan.baidu.com/s/1ge3eE2Z 密码:hox4 这部分我还没有完善全,正在努力中,应该大概需要1周左右的时间;如果没有百度云盘可以加入我QQ群:438836709,可以一起沟通学习Java的经验,群里面我也分享很多PDF的书籍,反正欢迎大家加入吧!当然我也会把这个文件完善以后上传到QQ群里面!!
深入理解Java虚拟机---学习感悟以及笔记的更多相关文章
- 深入理解java虚拟机学习笔记(一)JVM内存模型
上周末搬家后,家里的宽带一直没弄好,跟电信客服反映了N遍了终于约了个师傅明天早上来迁移宽带,可以结束一个多星期没网的痛苦日子了.这段时间也是各种忙,都一个星期没更新博客了,再不写之前那种状态和激情都要 ...
- 深入理解java虚拟机学习笔记(二)垃圾回收策略
上篇文章介绍了JVM内存模型的相关知识,其实还有些内容可以更深入的介绍下,比如运行时常量池的动态插入,直接内存等,后期抽空再完善下上篇博客,今天来介绍下JVM中的一些垃圾回收策略. 一. ...
- 深入理解Java虚拟机学习笔记(一)-----Java内存区域
一 概述 对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题 ...
- 深入理解Java虚拟机 - 学习笔记 1
Java内存区域 程序计数器 (Program Counter Register) 是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过 ...
- 深入理解java虚拟机学习笔记(二)
第三章 垃圾收集器与内存分配策略 概述 程序计数器.虚拟机栈.本地方法栈3个区随线程而生,随线程而灭.因此大体上可认为这几个区域的内存分配和回收都具备确定性.在方法/线程结束时,内存自然就跟着回收 ...
- 深入理解java虚拟机学习笔记(一)
第二章 Java内存区域与内存溢出异常 运行时数据区域 程序计数器(Program Counter Register) 程序计数器:当前线程所执行的字节码行号指示器.各条线程之间计数器互不影响,独立存 ...
- 深入理解Java虚拟机学习笔记(三)-----类文件结构/虚拟机类加载机制
第6章 类文件结构 1. 无关性 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(即扩展名为 .class 的文件) 是构成平台无关性的基石. 字节码(即扩展名为 .class 的文 ...
- 深入理解Java虚拟机学习笔记(二)-----垃圾收集器与内存分配策略
写在前面 本节常见面试题: 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何 ...
- 深入理解Java虚拟机 学习总结
一.运行时数据区域 Java虚拟机管理的内存包括几个运行时数据内存:方法区.虚拟机栈.本地方法栈.堆.程序计数器,其中方法区和堆是由线程共享的数据区,其他几个是线程隔离的数据区 1.1 程序计数器 程 ...
随机推荐
- 【原创】基于禅道的Bug管理操作规范
1. 禅道简介 禅道是一个基于"敏捷开发"模式的软件开发全生命周期管理软件,在国内的软件开发公司里占据了超过70%的份额,从大公司到小公司,都能适用. 禅道官网:http://ww ...
- python自动化运维七:fabric
p { margin-bottom: 0.25cm; line-height: 120% } a:link { } p { margin-bottom: 0.25cm; line-height: 12 ...
- net start mongodb 服务名无效解决方案
net start mongodb 服务名无效 或者 net start mongodb 发生错误5,拒绝访问.是因为没有用管理员权限运行cmd. 解决方案:在window中,在搜索框输入cmd后,在 ...
- bootstrap折叠调用collapse()后data-parent不生效问题
今天做的项目,用到了bootstrap的折叠功能,这个功能需要只展开一个折叠框,点击一个就会自动隐藏另一个,初始按照API做了一下,发现一切运行正常,但是测试的同事提了一个bug,说切换到其他模块后再 ...
- Java:什么是面向对象?
1.首先我们去区分对象的属性和方法. 一).什么是对象? 比如:所有的东西都可以叫做对象.而对象就是提供给我们研究对象,这就是对象. 二).怎么区分"属性"和"方法&qu ...
- Vue.js—快速入门
Vue.js是什么 Vue.js 是一套构建用户界面的渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目 ...
- nginx虚拟机配置(支持php)
由于本人水平有限,以下记录仅作参考. 下面贴出我的一份正常运行的nginx服务器虚拟机配置./usr/local/nginx/conf/vhost/www.xsll.com.conf server { ...
- yum常用选项和参数
列举包文件 # yum list #列出资源库中所有可以安装或更新的rpm包 # yum list updates #列出资源库中所有可以更新的rpm包 # yum list installed #列 ...
- Java面试题解构
有次一个同事让我一同去面试一个候选人,没仔细看简历,所以在问了设计模式之后就让他谈一谈对内存泄漏和垃圾回收的理解,当时候选人一下子就懵了.后来才知道,他面的是初.中级开发职位,想来估计候选人心里也在骂 ...
- C#递归查询
一.sql --构造测试数据: 只作演示用 CREATE TABLE [dbo].[Tim_LinqTable]( [Id] int PRIMARY KEY IDENTITY(1,1) NOT NUL ...