背景介绍
为什么我会去学习去了解JVM呢,因为在学习Java的时候,在一开始就提到了JVM,说到Java不是最好的语言,但是JVM是最好的虚拟机(今天我感受到了,垃圾回收,一会不使用之后就会清楚相关的对象,其中有着相关算法可以弱化引用),一开始我认为是因为它的**一次编译,都可运行,**然后之后学习到Java的面向对象的时候,我就不这么认为了,只是认为这只是一个优点,而关键点在GC垃圾回收机制。
推荐这本书,可以在番茄上找到"剑指JVM:虚拟机实践和性能调优",通过了解这本书,我学到了一些东西,大概如下吧。
首先,我将这个区域分为了四个区域,栈、堆、方法区、程序计数器
栈(Stack)
什么是栈?借助百度百科 定义堆栈又名栈(stack),它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
作为一种特殊的结构,它与递归是同种思想,总之,介绍的关键点不在他这个大的结构,而在于深入的内存结构。
虚拟机栈
虚拟机栈是JVM里的一种结构,它用来存储方法调用的状态信息(每个方法在执行过程中都会创建一个栈帧,存进虚拟机栈里面,当方法执行完的时候,就会将栈帧弹出虚拟机,就像上面说的出栈),包括局部变量表、操作数栈、动态链接、方法出口等等。
本地方法栈
这个本地方法栈和虚拟机栈很像,但是他存放的方法是本地方法,如C/C++
栈溢出总结
虚拟机栈溢出,是指虚拟机栈出现了内存溢出现象,即使用Java方法使用过多引起栈内存不足,例如无限深入递归调用方法
java
public class StackOverflowExample {
public static void recursiveMethod() {
recursiveMethod();
}
public static void main(String[] args) {
recursiveMethod();
}
}
本地方法栈溢出,是指本地方法栈出现了内存溢出现象,即使用本地方法过多,如本地方法链过长
如果需要的话,读者就自己写个c语言的方法,然后方法调用自己方法本身,代码逻辑基本和虚拟机栈溢出的代码一样。
但是他们都有一个共同之处,就是栈的溢出错误(StackOverFLowError),他们都是先进后出的结构,都是线程私有的。
堆(Heap)
在JVM中,堆是用来存储对象实例和数组的内存区域,为所有线程所共享。
学到了新东西(为什么要把数组不归为对象实例之中),因为
1.可以直接强调出来他的两个存储的功能,还能存储数组这种特殊对象,避免遗漏
2.在某些情况,如处理大量数据的时候,一部分数据用普通的对象,另一部分用数组来存储,数组的存储是连续紧密的,进行垃圾回收的时候,相较于普通对象存储的方式更便捷。
行到这里就先打住这个堆的原因了,介绍新生代和老年代
新生代(Young Generation)
新生代分为三个区域,Eden、from survivor、to survivor;
Eden区:
作用:
1.创建新对象的主要区域,当new 的时候会在这里分配空间;
2.空间相对其他地方比较大,可以用来频繁创建新对象
特点:
分配对象空间的速度很快,不用复杂的内存操作,大部分对象很快就会回收。
From survivor以及To survivor区
作用:
1.存放经过一次垃圾回收后仍然存活的对象
2.他们两个会轮回交替,现在是From等会可能就是to,再等会就又变成了From
特点:
空间相对Eden区比较小,经过多次垃圾回收之后,还存活的对象会晋升到老年代
老年代(Old Generation)
作用:存储活的比较久的对象,存储新生成的大对象;
特点:空间比新生代大很多,长期存活的对象和大对象需要更多空间
垃圾回收的频率相对新生代来说低很多,垃圾回收算法与新生代不同,回收时间较长
触发回收的情况:空间不足。
方法区(Method Area)
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器(jit)编译后的代码等数据的内存区域,可以理解为被识别过的数据,比较稳定的数据。
特点:
1.内存由所有线程共享,可以在不同线程访问同一个类的信息
2.相对稳定,跟栈和堆相比,数据还是比较稳定的,在程序运行期间一般不会发生变化,只有在类被卸载时才会释放方法区的内存。
3.垃圾回收,我没想到这里也有垃圾回收,主要是对不用的类进行卸载。
程序计数器(Program Counter Register)
作用:
1.指示当前执行指令的位置,他会存储当前线程正在执行的java方法的字节码指令的地址,然后当使用方法之后回来就是使用地址回来。
2。当使用另一个线程的时候结束的时候,可以指回来。
特点:
1.线程私有,每个线程都有一个
2.占用内存很小,就存一个字节码指令的地址
3.内存不会溢出,就存一个字节码指令的地址
总结
栈存储方法调用信息,堆存储对象实例,程序计数器指示执行位置,方法区存类信息等。它们相互协作,栈与堆通过对象引用关联,程序计数器与方法区配合执行指令,统一之后支持 Java 程序运行。
最关键的还是程序计数器,他就是整个流程的大脑。
如果我有哪里说得错了,希望可以指出,进步是需要的。