深入理解java虚拟机:笔记
1.运行时数据区域
1.程序计数器
当前线程执行字节码的行号指示器,字节码解释器工作通过改变这个计数器的值来选取下一条需要执行的字节码指令,每一个线程拥有独立的程序计数器,线程私有的内存
2.虚拟机栈
线程私有的内存,生命周期与线程相同,没有方法被执行会创建一个栈帧,存储局部变量表,操作栈等信息。
每一个方法被调用直至完成,对应一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表所需的内存空间在编译器完成分配,调用方法时在帧中分配多大的局部变量完全确定,运行时不会改变该表大小。
线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
若虚拟机栈动态扩展时无法申请到足够内存则会抛出OutOfMemoryError异常。
3.本地方法栈
与虚拟机栈作用类似,虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用到的native方法服务
4.java堆
被所有线程共享的内存区域,虚拟机启动时创建,存放对象实例:所有对象实例及数组在堆上分配(JIT编译发展已不是那么绝对)。
java堆是垃圾收集器管理的主要区域,也被称为gc堆,可以根据分代收集算法细分为:新生代,老年代.也可以分为Eden空间、From Survivor空间、To Survivor空间.从内存分配分多个线程私有的分配缓存区。
java堆可以处于物理上不连续的内存空间中,逻辑上可以连续,可以扩展(通过-Xmx 与-Xms控制)。
无法扩展时抛出OutOfMemoryError异常。
5.方法区(hotSpot虚拟机使用永久代来实现方法区)
与java堆一样时各个线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态常量、及时编译器编译后的代码等数据。
垃圾回收在这个区域比较少出现,回收目标主要针对常量池的回收和对类型的卸载,回收条件苛刻,但比较有必要。
无法满足内存分配需求时抛出OutOfMemoryError异常。
运行时常量池
方法区的一部分。Class文件编译期生成的各种字面量和符号引用,类加载后存放到方法区的运行时常量池中。
除了保存class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行常量池中。
运行时常量池相对class文件常量池具有动态性,运行期间也可能将新的常量放入池中。
无法满足内存分配需求时抛出OutOfMemoryError异常。
6.直接内存
并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是会频繁使用,当本机总内存不足时也会抛出OutOfMemoryError异常。
jdk中新加如的nio 可以使用native函数库直接分配堆外内存,然后通过存储在java队中的directByteBuffer对象作用这块内存的引用进行操作。
程序计数器\虚拟机栈\本地方法栈 三个区域随线程而生,随线程而灭.java堆和方法区内存分配回收动态的。
2.对象访问
不同虚拟机不访问对象方式不同:
使用句柄访问
java堆中划分内存作为句柄池,reference存储对象句柄地址,句柄包含实例数据(实例池)和类型数据(方法区)的具体地址信息。
使用指针访问(hotSpot虚拟机)
java堆放置访问类型数据的相关信息,reference中直接存储对象地址。
句柄访问好处是reference中存储稳定的句柄地址,对象移动(常见垃圾收集时)值会改变句柄中的实例指针。
指针访问好处是访问快,节省指针定位的时间开销。
3.垃圾收集器与内存分配策略:
gc成为系统达到更高并发量的瓶颈时,需要手动调节及监控。
判断对象是否存活
1.引用计数算法:对象添加引用计数,有引用它时,计数加1,引用失效,计数减1,计数为0时不被使用;但是难以解决循环引用。
2.根搜索算法:GC root对象作为起点,向下搜索,搜索走过的路径称为引用链,当一个对象到gc root不可达,则可以回收。
gc root对象包括以下几种:虚拟机栈(栈帧中的本地变量表)、方法区(类静态属性、常量)、本地方法栈JNI(native方法)中的引用的对象。
四种引用:
强引用(不会回收被引用对象);
软引用(发生溢出异常前列入回收范围之中),SoftReference;
弱引用(被引用对象生存到下次垃圾收集前),WeakReference;
虚引用(不会对其生存时间构成影响,无法通过虚引用取得对象实例,目的收集器回收时收到通知),PhantomReference;
对象回收:经历两次标记过程
发现无引用链,第一次标记并筛选是否必要执行finalize()方法,若有必要则放置F-Queue队列中,由虚拟机创建低优先级线程执行。
GC对F-Queue队列中的对象第二次标记,若此次标记移除,则可以逃脱。
finalize()适合使用的“关闭外部资源”的工作,使用try-finally或者其他方式使用更好。
方法区回收(hotSpot虚拟机永久代)主要回收:废弃常量和无用的类。
垃圾收集算法
标记-清除算法:先标记需要回收的对象,标记完成后统一回收掉被标记的对象。
效率问题,标记清除过程效率不高。
空间问题,清除后产出大量不连续内存碎片。
复制算法,在标记清除算法上解决效率问题(新生代)
将内存按容量划分为相等两块,每次使用其中一块,当这一块内存用完后,将还存活着的对象复制到另外一块上,再把已使用过的内存空间清理掉。
回收新生代,新生代回收并不是按照1:1划分内存,将内存分为较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor。
当回收时,将Eden和Survivor中还存活的对象一次性拷贝到另外的Survivor上,最后清理掉Eden和刚才用过的Survivor的空间(hotSpot虚拟机默认Eden和Survivor比例8:1)。
标记-整理算法,(老年代)
在标记清除算法上,标记后不直接清理可回收对象,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存
分代收集算法
根据对象的存活周期的不同将内存划分为几块,一般把java堆划分为新生代和老年代,这样可以根据各个年代的特点采用最适当的收集算法
垃圾收集器,不同虚拟机不同版本可能会有很大差别
Serial收集器,最基本最古老收集器,新生代收集器,单线程,简单高效,但是会停顿其他线程(Stop the world),直至收集结束。
ParNew收集器,新生代收集器,serial收集器多线程版,会暂停用户线程,但多线程进行GC回收。
Parallel Scavenge收集器,新生代收集器,使用复制算法,并行的多线程收集器,其主要目标是达到一个可控制的吞吐量,停顿时间越短越适合需要与用户交互的程序,而高吞吐量则可以高效利用cpu时间,适合后台运算而无需太多交互的任务。
Serial Old收集器Serial收集器老年代版本,单线程,使用标记整理。
Parallel Old收集器,老年代版本,多线程和标记整理算法,GC多线程且与用户线程同时进行。
CMS收集器,以获取最短回收停顿时间为目标的收集器,重视服务响应速度,基于标记-清除算法。
四步骤,初始标记、并发标记、重新标记、并发清除。优点:并发收集、低停顿。缺点:对cpu资源敏感、无法处理浮动垃圾、收集结束后会产生大量空间碎片。
G1收集器,基于标记-整理算法,不会产生空间碎片,可以精确控制停顿,收集范围为整个Java堆。
将java堆划分为多个大小固定的独立区域,跟踪区域内垃圾堆积程度,维护一个优先列表,根据允许的收集时间,优先回收垃圾最多的区域。
内存分配与回收策略
对象优先在java堆中的新生代Eden区中分配,若空间不足,发起一次Minor GC。
大对象(需要大量连续内存空间的java对象)直接进入老年代,避免Eden区及两个Survivor区发生大量复制。
长期存活的对象将进入老年代,虚拟机给每个对象定义了年龄计数器,每过一次Minor GC加一,默认加至15,将该对象晋升至老年代。
动态年龄判断,如果在Survivor空间相同年龄所有对象大小的综合大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
4.虚拟机性能监控与故障处理工具
命令行工具
jps:
列出正在运行的虚拟机进程,并显示虚拟机执行主类,及这些进程的本地虚拟机唯一id,例如:
D:\java\bin>jps
RemoteMavenServer
Jps
jstat:
显示本地或远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,例如:
D:\java\bin>jstat -gc
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
48128.0 512.0 0.0 0.0 147456.0 11172.5 175104.0 10777.7 28032.0 26797.1 3456.0 3065.7 0.591 1.066 1.657
jinfo:
实时查看和调整虚拟机各项参数,例如查询pid为11996的各项参数:
D:\java\bin>jinfo -flags
jmap:
用于生成堆转储快照(heapdump或dump文件),还可以查询finalize执行队列,堆和永久代详细信息,例如生成正在运行idea的dump快照文件:
D:\java\bin>jmap -dump:format=b,file=idea.bin
Dumping heap to D:\java\bin\idea.bin ...
Heap dump file created
jhat:
虚拟机堆转储快照分析,分析jmap生成的dump文件,例如分析上述例子中生成的idea.bin文件
D:\java\bin>jhat idea.bin
Reading from idea.bin...
Dump file created Thu Oct :: CST
Snapshot read, resolving...
Resolving objects...
Chasing references, expect dots...............
.........................
Eliminating duplicate references.................
.......................
Snapshot resolved.
Started HTTP server on port
Server is ready.
然后在浏览器中输入http://localhost:7000/查看
jstack:
java堆栈跟踪工具,用于生成虚拟机当前时刻的线程快照。线程快照就是当期虚拟机内每一条线程正在执行的方法堆栈集合,定位线程出现长时间停顿的原因,例如:
D:\java\bin>jstack -l
可视化工具
JConsole:Java监视与管理控制台
内存监控:用于受收集器管理的虚拟机内存(java堆和永久代)的变化趋势,可视化jstat命令
线程监控:可视化jstack命令
jvisualvm:多合一故障处理工具,一个代替上面所有
深入理解java虚拟机:笔记的更多相关文章
- Java内存区域与内存溢出异常——深入理解Java虚拟机 笔记一
Java内存区域 对比与C和C++,Java程序员不需要时时刻刻在意对象的创建和删除过程造成的内存溢出.内存泄露等问题,Java虚拟机很好地帮助我们解决了内存管理的问题,但深入理解Java内存区域,有 ...
- 深入理解java虚拟机笔记Chapter12
(本节笔记的线程收录在线程/并发相关的笔记中,未在此处提及) Java内存模型 Java 内存模型主要由以下三部分构成:1 个主内存.n 个线程.n 个工作内存(与线程一一对应) 主内存与工作内存 J ...
- 深入理解Java虚拟机笔记
1. Java虚拟机所管理的内存 2. 对象创建过程 3. GC收集 4. HotSpot算法的实现 5. 垃圾收集器 6. 对象分配内存与回收细节 7. 类文件结构 8. 虚拟机类加载机制 9.类加 ...
- 深入理解java虚拟机笔记Chapter7
虚拟机类的加载机制 概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类的加载机制. 类加载的时机 J ...
- 深入理解java虚拟机笔记之一
Java的技术体系主要有支撑java程序运行的虚拟机,提供各开发领域接口支持Java API,java编程语言及许多第三方java框架( 如Spring,Structs等)构成. 可以把Java程序设 ...
- 深入理解Java虚拟机笔记——虚拟机类加载机制
目录 概述 动态加载和动态连接 类加载的时机 类的生命周期 被动引用 例子一(调用子类继承父类的字段) 例子二(数组) 例子三(静态常量) 类加载的过程 加载 验证 准备 解析 符号引用 直接引用 初 ...
- 【转载】深入理解Java虚拟机笔记---运行时栈帧结构
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法的局部变量表,操作 ...
- 深入理解java虚拟机笔记Chapter8
运行时栈帧结构 栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法 ...
- 深入理解java虚拟机笔记Chapter2
java虚拟机运行时数据区 首先获取一个直观的认识: 程序计数器 线程私有.各条线程之间计数器互不影响,独立存储. 当前线程所执行的字节码行号指示器.字节码解释器工作时通过改变这个计数器值选取下一条需 ...
- 类文件结构——深入理解Java虚拟机 笔记三
在之前的笔记中记录过,Java程序变成可执行文件的步骤是:源代码-->经过编译变成class文件-->经过JVM虚拟机变成可执行的二进制文件.因此,为了对JVM执行程序的过程有一个好的了解 ...
随机推荐
- WRNavigationBar 使用记录
最近在做一个导航栏透明度渐变的效果,发现 WRNavigationBar库很好用,一开始导入到项目,发现导航tiltle颜色一直是黑色的,无论怎么用系统方法改都改不了.后来发现原来库里面有一个方法可以 ...
- git查看切换分支
Git一般有很多分支,我们clone到本地的时候一般都是master分支,那么如何切换到其他分支呢?主要命令如下: 1. 查看远程分支 $ git branch -a 我在mxnet根目录下运行以上命 ...
- delphi 使用 InputBox、InputQuery 的启发
使用 InputBox.InputQuery 的启发 看了 InputBox.InputQuery 函数实现的源码, 有些收获与心得... ------------------------------ ...
- VSphere随笔 - vCenter6.5安装报错 “Failed to authenticate with the guest operating system using the supplied“
今天重新安装VCSA,安装多次一直卡在80%的画面不动,显示正在安装RPM包,同时log日志显示“Failed to authenticate with the guest operating sys ...
- TestStack.White安装详解
一.安装 NuGet TestStack.White是通过NuGet进行安装的.NuGet最低支持VS2010.我使用的VS2015. 安装方式一 :从Visual Studio的工具->扩展和 ...
- 读取 appsettings.json
Appsettings.json 配置: 个配置文件就是一个json文件,并且是严格的json文件,所有的属性都需要添加“”引号.下图是一个常规的代码示例: {"UrlString" ...
- laravel 向多视图及所有视图传递数据变量
向单个视图传递变量 1.使用with()方法 : view('user.lists')->with('title',$title); 2.直接view()传参: view('user.lists ...
- Linux操作系统(三)_部署JDK
一.通过tar.gz压缩包安装 1.在usr目录下创建java目录 cd usr mkdir java 2.用rz命令上传tar.gz安装包到java目录 3.解压tar.gz安装包到当前目录 tar ...
- 干货 | Bokeh交互式数据可视化快速入门
Bokeh简介 Bokeh是一款交互式可视化库,在浏览器上进行展示. Bokeh可以通过Python(或其它语言),快速便捷地为大型流数据集提供优雅简洁的高性能交互式图表. 安装 在python中有多 ...
- Java享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern)主要用于减少创建的对象数量,并减少内存占用并提高性能. 这种类型的设计模式属于结构模式,因为该模式提供了减少对象计数的方法,从而改善应用的对象结构. 享元 ...