重读《深入理解Java虚拟机》
Posted 求知若饥虚心若愚,脚着沃野长望星空,天高海阔水静深流.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重读《深入理解Java虚拟机》相关的知识,希望对你有一定的参考价值。
一、Java虚拟机内存区域如何划分
1、Java虚拟机内存区域的划分
| 区域名称 | 作用(用途) | 类型 | 特点 | 虚拟机规定异常情况 | 其他说明 |
1 | 程序计数器 | 指示当前正在执行的字节码指令地址 | 线程私有 | 1、内存空间较小 2、随用户进程的启动和结束而建立和销毁。 | 无 | 每个线程都有独立的程序计数器。执行Native方法时为空指针。 |
2 | 虚拟机栈(栈内存) | Java方法执行的内存模型(方法栈帧入栈、出栈)。每个方法执行的时候都会创建一个栈帧用于存储局部变量表、操作数,动态链接、方法出口等。 为虚拟机执行Java方法服务,用于执行Java方法 | 线程私有 | 1、内存空间较小 2、随用户进程的启动和结束而建立和销毁 | 1、StackOverflowError:线程请求栈深大于虚拟机所允许的栈深。 2、OutMemoryError:如虚拟机栈可以动态扩展,如果在扩展时无法申请到足够的内存时抛出异常 | 局部变量表:用于存放编译期可知的类型,包括基本类型,引用类型,returnAddress类型。局部变量表所需内存空间在编译期已完成分配,运行期不改变局部变量表大小。 |
3 | 本地方法栈 | 为虚拟机使用到的Native方法服务即用于执行Native方法 | 线程私有 | 1、内存空间较小 2、随用户进程的启动和结束而建立和销毁 | 1、StackOverflowError: 2、OutMemoryError: | |
4 | 堆(GC堆,堆内存) | 用于存放对象实例,几乎所有的对象实例都在这里分配 | 线程共享 | 1、内存空间较大; 2、随虚拟机进程启动而创建 3、垃圾收集器主要管理的区域 4、不需要连续的内存空间,只要逻辑上连续即可 | 1、OutMemoryError:堆中没有内存可用于完成实例分配,并且堆也无法再扩展的时候抛出 | 1、根据垃圾收集器实现算法(分代收集算法)分为:Eden空间、From Survivor空间、ToSurvivor空间。(新生代,老年代) 2、从内存分配角度:堆可划分为多个线程私有的分配缓存区,目的是为了更好的回收内存和更快的分配内存 |
5 | 方法区(非堆) | 用于存储虚拟机已经加载的类信息、常量、静态变量、即时编译器编译后的代码等(存放Class的相关信息如类名,访问修饰符,常量池,字段描述,方法描述等) | 线程共享 | 1、堆内存的一个逻辑部分 2、内存回收主要针对常量池的回收和类型的卸载 | 1、OutMemoryError:方法去无法满足内存分配需求时抛出,即没有足够的内存用于分配 | 运行常量池:用于存放编译期生成的各种字面量和符号引用,在类加载后进入运行时常量池时存放。运行时常量池具备动态性即常量可以在编译期内产生也可以在运行期添加新的常量··· |
直接内存不是Java内存区域。
2、堆内存空间内:对象实例的创建、内存布局和内存定位
(1)堆内存空间内对象如何创建分配
1)根据new指令的类型常量在常量池内定位到该类型的符号引用、并判断该类是否已加载、解析和初始化
2)如果判断类型信息未加载则进行加载
3)在堆内分配指定大小的堆内存空间
如何分配堆内存空间:a、指针碰撞:即堆内存空间物理上是连续分配的,分配相对规整的,在用过的内存往未用过的内存方向进行分配
b、空闲列表:即堆内存空间不是规整分配的,使用一个空闲列表记录当前未分配的内存空间,分配时在该空闲列表内查询符合指定大小的内存空间进行分配
如何保证内存分配的正确性:线程私有分配缓冲区(TLAB),每个线程独立分配一块小内存区域(本地线程分配缓冲),每个线程只在自己的TLAB内分配实例对象。设置TLAB:-XX:+/-UseTLAB
4)自动初始化:初始化内存空间的默认值
5)设置对象头信息
6)执行init初始化方法按照对象声明位置进行初始化
(2)堆内存空间内对象如何布局
1)对象头
2)实例数据
3)对齐
(3)堆内存空间内对象如何定位
1)句柄
2)直接指针
3、OOM异常调试和参数设置
溢出区域 | 参数设置 | 异常抛出条件 | 其他说明 |
堆 | -Xms -Xmx | 堆内存无法自动扩展,没有足够内存分配实例对象 | 设置参数-XX:+HeapDumpOnOutMemoryError在出现异常时Dump出现当前内存堆转储快照用于事后分析 |
虚拟机栈和本地方法 | -Xss:设置虚拟机栈大小 -Xoss:设置本地方法大小 | 1、StackOverflowError:线程请求栈深大于虚拟机所允许的栈深。 2、OutMemoryError:如虚拟机栈可以动态扩展,如果在扩展时无法申请到足够的内存时抛出异常 | 每个线程分配的虚拟机栈容量越大,则可建立的线程数就越少 |
方法区和运行时常量 | -XX:PermSize方法区最小容量 -XX:MaxPermSize:最大方法区容量 | 1、OutMemoryError:方法去无法满足内存分配需求时抛出,即没有足够的内存用于分配 | |
直接内存 | -XX:MaxDirectMemorySize:指定直接内存最大容量,如果不指定默认与堆同等大小容量 | 1、OutMemoryError:方法去无法满足内存分配需求时抛出,即没有足够的内存用于分配 | 不属于Java内存区域 直接内存=物理内存-各个区域内存总和 |
二、如何实现垃圾收集和内存分配
三、虚拟机性能如何监控、如何处理故障、如何分析
四、Java程序如何存储(类文件结构)
五、Java程序如何载入(类的加载机制)
六、Java程序如何执行(虚拟机字节码执行引擎)
七、Java程序代码如何优化
八、Java的内存模型
九、Java线程
以上是关于重读《深入理解Java虚拟机》的主要内容,如果未能解决你的问题,请参考以下文章
重读《深入理解Java虚拟机》虚拟机如何执行字节码?虚拟机执行引擎的工作机制