wordpress建站侵权,怎样是做网站,湖北省建设厅乡镇污水官方网站,网站规划和布局系列文章目录
第一章 运行区实验 文章目录 系列文章目录前言一、堆#xff08;Heap#xff09;1.1、新生代/Young区1.1.1、Eden区1.1.2、Survival区 1.2、年老代#xff08;old区#xff09; 二、虚拟机栈#xff08;Stack#xff09;2.1、栈顶缓存技术2.2、溢出2.3、栈…系列文章目录
第一章 运行区实验 文章目录 系列文章目录前言一、堆Heap1.1、新生代/Young区1.1.1、Eden区1.1.2、Survival区 1.2、年老代old区 二、虚拟机栈Stack2.1、栈顶缓存技术2.2、溢出2.3、栈帧2.3.1、局部变量表local variables2.3.2、操作数栈Operand Stack LIFO2.3.3、动态链接2.3.4、方法返回地址2.3.5、额外信息 三、方法区MetaData Space3.1、方法区和永久代的关系 四、本地方法栈Native Method Stacks五、程序计数器六、直接内存Direct Memory总结 前言
JVMJava虚拟机运行区是Java程序在运行过程中被JVM所管理的内存区域。它包括了Java程序运行时的堆Heap、栈Stack、方法区Method Area、本地方法栈Native Method Stacks、程序计数器和直接内存Direct Memory等部分。 一、堆Heap
堆Heap是Java程序运行时用于动态分配内存的区域也是Java垃圾收集器进行垃圾回收的主要区域。堆内存被所有线程共享。
以JDK8为例堆Heap用来存放对象几乎所有逃逸分析技术栈上分配、标量替换对象都在堆上分配将Java堆细分的目的只是为了更好地回收内存或者更快地分配内存堆中没有内存分配对象并且无法扩展时会抛出OutOfMemoryError异常。
堆Heap一般管理新生代/Young区 、年老代old区 、String字符串常量池。
1.1、新生代/Young区
新生代里包含Eden区 与 Survival区2个区。
1.1.1、Eden区
Eden区位于Java堆的年轻代是新对象分配内存的地方由于堆是所有线程共享的因此在堆上分配内存需要加锁。而Sun JDK为提升效率会为每个新建的线程在Eden上分配一块独立的空间由该线程独享这块空间称为TLABThread Local Allocation Buffer。在TLAB上分配内存不需要加锁因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配。如果对象过大或TLAB用完则仍然在堆上进行分配。如果Eden区内存也用完了则会进行一次Minor GCyoung GC。
1.1.2、Survival区
Survival区与Eden区相同都在Java堆的年轻代。Survival区有两块一块称为from区另一块为to区这两个区是相对的在发生一次Minor GC后from区就会和to区互换。在发生Minor GC时Eden区和Survival from区会把一些仍然存活的对象复制进Survival to区并清除内存。Survival to区会把一些存活得足够旧的对象移至年老代。
1.2、年老代old区
年老代里存放的都是存活时间较久的大小较大的对象因此年老代使用标记整理算法。当年老代容量满的时候会触发一次Major GCfull GC回收年老代和年轻代中不再被使用的对象资源
二、虚拟机栈Stack
每个线程在创建时都会创建一个私有的JVM栈。每个方法执行的时候都会创建一个栈帧用于存储局部变量、操作数栈、常量池引用等信息。如下图栈帧1、栈帧2、栈帧3、栈帧N。
2.1、栈顶缓存技术
解释执行状态下将访问最频繁的数据程序计数器、栈顶缓存在物理CPU的寄存器中以此降低对内存的读/写次数提升执行引擎的执行效率。
2.2、溢出
如果线程请求的栈深度大于虚拟机所允许深度将抛出StackOverflowError异常如果Java虚拟机栈容量可以动态扩展 当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。
发生StackOverflowError异常使用死循环递归代码可以复现。 可以使用参数-Xss选项来设置线程的最大栈空间例如-Xss265k
2.3、栈帧
栈的存储单位为栈帧线程上正在执行的一个方法对应一个栈帧栈帧是一个内存区块是一个数据集维系着方法执行过程中的各种数据信息。
每个栈帧包含五部分分别包括局部变量表、操作数栈、动态链表指向运行时常量池的方法引用、方法返回地址和一些额外信息。
2.3.1、局部变量表local variables 局部变量表定义为一个数字数组主要用于存储方法参数和定义在方法体内的局部变量这些数据类型包括各种基本数据类型、对象引用reference以及returnAddress类型。 由于局部变量表是线程的私有数据不存在线程的安全问题 局部变量表所需容量大小在编译器确定下来的并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。 局部变量表的变量只在当前方法调用中有效的当方法调用结束后随着方法栈帧的消耗局部变量表也会随之销毁。 局部变量表的最基本存储单位是Slot变量槽32位以内的类型只占用一个slot包括returnAddress类型引用类型64位的类型long和double占用两个slot。 每一slot都分配一个访问索引占用两个slot的变量只需要使用前一个索引即可 构造方法或者实例方法非static该对象引用this将会存放在index为0的slot处 局部变量表的变量也是重要的垃圾回收根节点只要被局部变量表中直接或间接引用的对象都不会被回收。
2.3.2、操作数栈Operand Stack LIFO
编译后 .Class文件的Code属性的max_stacks数据记录操作数栈的最大深度操作数栈在方法执行过程中根据字节码指令往栈中写入数据或提取数据即入栈或者出栈使用数组实现操作数栈主要用于保存计算过程的中间结果同时作为计算过程中变量临时的存储空间。
2.3.3、动态链接
运行期间把常量池中的符号引用转换成直接引用的过程叫做动态链接 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用持有这个引用是为了支持方法调用过程中的动态链接。
2.3.4、方法返回地址
方法返回地址存储的是调用该方法的pc寄存器的值。方法正常退出时调用者的pc计数器的值作为返回地址即调用该方法的指令的下一条指令的地址。
2.3.5、额外信息
Java虚拟机规范允许虚拟机实现在栈帧之中增加一些规范里没有描述的信息例如与调试、性能收集相关的信息。
三、方法区MetaData Space
方法区(MetaData Space 元空间)/Non-Heap用于存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
3.1、方法区和永久代的关系
在JDK1.8之前习惯把方法区称为“永久代”。HotSpot 虚拟机在1.7之前使用永久代来管理实现方法区使得jvm的垃圾回收器能像管理堆内存一样来管理永久代这部分内存而不用专门为方法区编写内存管理代码。但这种设计使得虚拟机更容易出现内存溢出问题而不像J9和JRockit只要没有触碰到进程可用内存的上限32位4GB就没有问题。 JDK1.7把原本放在永久代的字符串常量池、静态变量等移出主要剩余类型信息 JDK1.8完全废弃了永久代的概念改用与JRockit、J9一样在本地内存中实现的元空间方法区无法满足新的内存分配需求时将抛出OutOfMemoryError异常。
四、本地方法栈Native Method Stacks
Native Method Stacks 为虚拟机使用到的本地Native方法服务本地方法栈也会在栈深度溢出或者栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。
五、程序计数器
程序计数器当前线程所执行的字节码的行号指示器字节码解释器工作时通过改变计数器的值执行下一条指令此内存是JVM规范中唯一一个没有OutOfMemoryError的区域。
六、直接内存Direct Memory
DM并不是虚拟机运行时数据区的一部分也不是《Java虚拟机规范》中定义的内存区域。但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现例如NIO 中的 DirectByteBuffer 直接操作堆外内存避免在Java堆和Native堆中来回复制数据。
同时也可以关注零拷贝(DMA)技术的应用。 总结
这些内存区域的管理和优化对于Java程序的性能和可靠性至关重要。