一、前言
若想自己编写的Java
程序高效运行,以及进行正确、高效的异常诊断,JVM
是不得不谈的一个话题。本”JVM进阶“专栏大部分内容均来源于经典书籍《深入理解Java虚拟机
》。
二、栈存储
言归正传,本文重点从虚拟机内存模型(运行时数据区域)入手。先看下图:
这是一张比较官方的虚拟机模型图,今天讲的就是虚线框中栈的部分。
栈是我们最常用的内存区域。它主要用来存放基本类型变量,局部变量以及对象的引用。例如:User user = new User();
这里的user就是对象的引用也可以理解为地址,指引着虚拟机要去哪里找user这个对象。 他们的基本关系如图:
由上图可知,当我们将一个对象作为方法的参数时,我们在方法中改变对象的值,也会影响到原来对象的值,因为我们只是改变了图中内存区域的值,他的指引(地址)还是一样的。同时也可以看出,栈的内存区域是连续的,有大小限制的,如果超过了就会抛出栈溢出的异常StackOverflowError
。
在每个方法执行的时候,都会创建一个个的栈帧,用于保存局部变量表,操作数栈,动态链接等信息(以后都会详细讲解)。每次方法的调用都会对应着一个栈帧,因此可以解释当我们在写递归程序的时候会不小心报栈溢出的异常,因为栈是有限的,方法调用太多次导致栈帧堆满了栈,所以溢出。看下面代码:
public class Test {
private static int stackLength = 0;
private static void main(String[] args) {
try {
Test test = new Test();
test.stackOverFlow();
} catch (Throwable e) {
System.out.println("stackLength:" + stackLength);
throw e;
}
}
public void stackOverFlow() {
// 疯狂递归调用
stackLength++;
stackOverFlow();
}
}
在参数-Xss128k
的情况下的报错。(eclipse
中设置参数:右键代码选择Run As-->Run Configurations
,在Arguments栏下的VM arguments
中填入参数,再Apply,再run)
每次在方法执行完毕的时候,虚拟机会自动释放掉为该栈所分配的空间,在栈中,对应着一个栈帧的出栈。虚拟机会自动分配与回收内存,因此效率比较高。
三、总结
最后做一下栈的总结:
- 存放基本类型变量,局部变量,对象的引用;
- 系统自动分配与回收内存,效率较高,快速,存取速度比堆要快;
- 是一块连续的内存的区域,有大小限制,如果超过了就会栈溢出,并抛出栈溢出的异常
StackOverflowError
;Java
会自动释放掉为该变量所分配的内存空间;
栈又分为java栈和本地方法栈。顾名思义,本地方法栈自然就是为本地方法提供服务的,java栈是为java
服务的。
注意⚠️:JVM栈
是每个线程私有的!
四、延伸阅读 编译型语言与解释型语言
计算机只能识别二进制指令,不能直接识别由JavaScript
等高级编程语言所编写的代码(源代码),所以需要将高级语言转为二进制指令。
由于不同语言转换为二进制指令的时机不同,可分为编译型语言和解释性语言。
4.1 编译型语言
编译型语言要求使用编译器一次性将所有源代码编译为一个可执行程序,一次编译可重复执行。代表语言有C
、C++
、Golang
、汇编
等。
● 编译型语言一般不能跨平台
- 编译出来的可执行程序不能跨平台:因为不同操作系统对可执行文件有着不同的要求,彼此之间不能兼容。
- 源代码不能跨平台:不同操作系统下的函数、变量、api等可能会有不同。
4.2 解释型语言
解释型语言是使用解释器一边执行一边转换,用到些源代码就转换哪些,不会生成可执行程序。代表语言有JavaScript
、Python
、PHP
、Shell
等。
● 解释型语言一般可以跨平台
跨平台是指源代码可以跨平台,解释器是不能跨平台的。源代码在不同操作系统中运行的结果相同。
五、拓展阅读
- 《JVM虚拟机专栏》
总结
前端资料汇总
-
框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。
-
算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯
-
在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。
-
要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!
喜欢这篇文章文章的小伙伴们点赞+转发支持,你们的支持是我最大的动力!