Java教程

自动内存管理

本文主要是介绍自动内存管理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

运行时数据区域

![image.png](https://www.www.zyiz.net/i/ll/?i=img_convert/a754dc19c4f3dba33e7a55c83b95f6a2.png#height=653&id=eGQ8e&margin=[object Object]&name=image.png&originHeight=653&originWidth=820&originalType=binary&ratio=1&size=266525&status=done&style=none&width=820)
运行时数据区域

程序计数器(Program Counter Register)

字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处
理、线程恢复等基础功能都需要依赖这个计数器来完成。
并且由于Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器。

Java虚拟机栈(Java Virtual Machine Stack)

线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行的时候,Java虚拟机都
会同步创建一个栈帧[1](Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

局部变量表存放了编译期可知的各种Java虚拟机基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址)。在局部变量表中的存储空间以局部变量槽(Slot)来表示其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配、方法运行期间不会改变局部变量表的大小(指槽的数量)。

本地方法栈(Native Method Stacks)

与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。

Java堆(Java Heap)

Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。所有的对象实例以及数组都应当在堆上分配。
Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。

方法区(Method Area)

是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

运行时常量池在方法区中。
JDK7以前,字符串常量池存放在永久代中。但在JDK7及以后,字符串常量池存放在Java堆中。

运行时常量池(Runtime Constant Pool)

是方法区的一部分。

直接内存(Direct Memory)

默认大小与堆的最大值一致。

常见的溢出表现为,内存溢出但是Dump很小,需要考虑是否操作堆外内存,如:NIO就使用Native函数库直接分配堆外内存。

区域大小设置

其中用永久代来实现方法区,说明是JDK8以前的。
![JVM内存结构以及对应参数.jpg](https://www.www.zyiz.net/i/ll/?i=img_convert/0bf262bddde7ed377ee8cbd6d255522b.png#height=281&id=oMBYT&margin=[object Object]&name=JVM内存结构以及对应参数.jpg&originHeight=281&originWidth=720&originalType=binary&ratio=1&size=29499&status=done&style=none&width=720)
JDK8以后,需要这样设置:
-XX:MaxMetaspaceSize:设置元空间最大值,默认是-1,即不限制(只受限于本地内存大小)。
-XX:MetaspaceSize:指定元空间的初始空间大小,单位:Byte(字节),达到该值会触发垃圾收集进行类型卸载,并调整大小。
-XX:MinMetaspaceFreeRadio:控制在垃圾收集之后的最小元空间百分比。

元空间(Metaspace)的历史

在HotSpot虚拟机中,使用永久代来实现方法区,但到了JDK7时,已经把存放在永久代中的字符串常量池、静态变量等移出(放到堆中),到了JDK8完全废弃了永久代的概念,改用本地内存中实现的元空间来代替。并且把JDK7中还剩余的内容(主要是类信息)全部移到元空间中。

这篇关于自动内存管理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!