JVM的内存模型

什么是JVM?

JVM是Java Virtual Machine(Java虚拟机)的简称。

使用JVM的优点?

1、通过JVM,我们可以屏蔽各种系统的底层区别,让java程序,一次编写,到处运行。
2、通过JVM的垃圾回收机制,让java自动进行内存的管理。开发者大部分情况不需要关心内存本身,可以专注业务开发。

JVM的内存模型


如图所示,JVM的内存模型共分为5个区:堆(Heap)、方法区(Method Area)、程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)。

堆(Heap)

堆是JVM内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。

堆被划分为新生代和老年代,新生代又被进一步划分为Eden区和Survivor区,Survivor由From Survivor和To Survivor组成。

在Java6版本中,永久代在非堆内存区;到了Java7版本,永久代的静态变量和运行时常量池被合并到了堆中;而到了Java8,永久代被元空间(处于本地内存)取代了。

方法区(Method Area)

方法区主要是用来存放已被虚拟机加载的类相关信息,包括类信息、常量池(字符串常量池以及所有基本类型都有其相应的常量池)、运行时常量池。这其中,类信息又包括了类的版本、字段、方法、接口和父类等信息。

程序计数器(Program Counter Register)

程序计数器是一块很小的内存空间,主要用来记录各个线程执行的字节码的地址,例如,分支、循环、跳转、异常、线程恢复等都依赖于计数器。当一个线程的时间片用完了,这个退出的线程就需要单独的一个程序计数器,来记录下一条运行的指令,所以程序计数器和上下文切换有关。

虚拟机栈(VM Stack)

虚拟机栈是线程私有的内存空间,它和Java线程一起创建。当创建一个线程时,会在虚拟机栈中申请一个线程栈,用来保存方法的局部变量、操作数栈、动态链接方法和返回地址等信息,并参与方法的调用和返回。每一个方法的调用都伴随着栈帧的入栈操作,方法的返回则是栈帧的出栈操作。

可以这么理解,虚拟机栈针对当前 Java 应用中所有线程,都有一个其相应的线程栈,每一个线程栈都互相独立、互不影响,里面存储了该线程中独有的信息。

本地方法栈(Native Method Stack)

本地方法栈跟虚拟机栈的功能类似,虚拟机栈用于管理Java方法的调用,而本地方法栈则用于管理本地方法的调用。但本地方法并不是用Java实现的,而是由C语言实现的,在代码中用native进行修饰。

内存溢出

1、在这5块区域中,不会发生内存溢出的区域为“程序计数器”,其他区域均有可能发生内存溢出。
2、当我们不停地new对象且不释放引用的话,则“堆”内存会越来越大,且由于引用还存在,垃圾回收器无法进行GC,最终“堆”发生内存溢出。OutOfMemoryError
3、当我们方法循环递归调用时,线程栈中不停地入栈栈帧,没有出栈,内存也会越来越大,最终“栈”发生内存溢出。StackOverflowError
4、方法区主要存放类相关的信息,而java在使用cglib动态代理类时,是通过加载字节码,修改字节码,最后生成子类(代理类)的方式实现的,所以使用cglib无限创建动态代理类时,最终也有可能会发生内存溢出。


觉得内容还不错?打赏个钢镚鼓励鼓励!!👍