发布于2021-05-29 19:15 阅读(866) 评论(0) 点赞(6) 收藏(0)
如图所示:
Java指令执行流程:
.java
代码源文件经过编译为.class
二进制字节码文件。
.class
文件中的每一条二进制字节码指令(JVM指令) 通过 解释器 转换成 机器码 然后就可以被 CPU 执行了!
- 当 解释器 将一条 jvm 指令转换成 机器码 后,同时会向程序计数器 递交下一条 jvm 指令的执行地址!
如图所示:
实例代码:
/**
* @Auther: csp1999
* @Date: 2020/11/10/11:36
* @Description: 演示栈帧
*/
public class Demo01 {
public static void main(String[] args) {
methodA();
}
private static void methodA() {
methodB(1, 2);
}
private static int methodB(int a, int b) {
int c = a + b;
return c;
}
}
流程分析:
我们打断点来Debug 一下看一下方法执行的流程:
接这往下走,使方法B执行完毕:
然后方法A 执行完毕,其对应的栈帧出栈,main 方法对应的栈帧为活动栈帧;最后main执行完毕,栈帧出栈,虚拟机栈为空,代码运行结束!
一些带有native 关键字修饰的方法就是需要JAVA去调用本地的C或者C++方法,因为JAVA有时候没法直接和操作系统底层交互,所以需要用到本地方法!
new
关键字创建的对象都会被放在堆内存。-Xmx -Xms:
JVM初始分配的堆内存由-Xms
指定,默认是物理内存的1/64
。(java.lang.OutOfMemoryError:PermGen space、java.lang.OutOfMemoryError:Metaspace)
。方法区的演进:
1.6 版本方法区是由 永久代 实现(使用堆内存的一部分作为方法区),且由JVM 管理。由Class、ClassLoader、常量池(包括StringTable) 组成。
Jdk 1.7 版本仍有永久代,但已经逐步 " 去永久代 ",StringTable、静态变量从永久代移除,保存在堆中。
1.8 版本后,方法区交给本地内存管理,而脱离了JVM,由元空间实现(元空间不再使用堆的内存,而是使用本地内存,即操作系统的内存),由Class、ClassLoader、常量池(StringTable 被移到了堆中管理) 组成。
常量池:可以看做是一张表,虚拟机指令根据这张常量表找到要执行的 类名,方法名,参数类型、字面量 等信息。
*.class
文件中的,当该类被加载以后,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实内存地址。运行时常量池:是方法区的一部分。
String str = new String("hello");
上面的语句中变量 str
放在栈上,用 new 创建出来的字符串对象放在堆上,而hello
这个字面量是放在堆中。
我们来看一张图:
我们通过两张图去分析一下:
从图中得出:局部变量如果是静态的可以被多个线程共享,那么就存在线程安全问题。如果是非静态的只存在于某个方法作用范围内,被线程私有,那么就是线程安全的!
再来看一个案例:
/**
* 局部变量的线程安全问题
*/
public class Demo02 {
public static void main(String[] args) {// main 函数主线程
StringBuilder sb = new StringBuilder();
sb.append(4);
sb.append(5);
sb.append(6);
new Thread(() -> {// Thread新创建的线程
m2(sb);
}).start();
}
public static void m1() {
// sb 作为方法m1()内部的局部变量,是线程私有的 ---> 线程安全
StringBuilder sb = new StringBuilder();
sb.append(1);
sb.append(2);
sb.append(3);
System.out.println(sb.toString());
}
public static void m2(StringBuilder sb) {
// sb 作为方法m2()外部的传递来的参数,sb 不在方法m2()的作用范围内
// 不是线程私有的 ---> 非线程安全
sb.append(1);
sb.append(2);
sb.append(3);
System.out.println(sb.toString());
}
public static StringBuilder m3() {
// sb 作为方法m3()内部的局部变量,是线程私有的
StringBuilder sb = new StringBuilder();// sb 为引用类型的变量
sb.append(1);
sb.append(2);
sb.append(3);
return sb;// 然而方法m3()将sb返回,sb逃离了方法m3()的作用范围,且sb是引用类型的变量
// 其他线程也可以拿到该变量的 ---> 非线程安全
// 如果sb是非引用类型,即基本类型(int/char/float...)变量的话,逃离m3()作用范围后,则不会存在线程安全
}
}
所以,该面试题答案是:
如图所示,就是栈中栈帧过多的情况:
1.6 版本方法区是由永久代实现(使用堆内存的一部分作为方法区),且由JVM 管理。由Class、ClassLoader、常量池(包括StringTable) 组成。
Jdk 1.7 版本仍有永久代,但已经逐步 " 去永久代 ",StringTable、静态变量从永久代移除,保存在堆中。
1.8 版本后,方法区交给本地内存管理,而脱离了JVM,由元空间实现(元空间不再使用堆的内存,而是使用本地内存,即操作系统的内存),由Class、ClassLoader、常量池(StringTable 被移到了堆中管理) 组成。
为什么要用元空间取代永久代?
因为永久代有以下几个弊端:
以 JDK 8 为例:
名称 | 加载哪的类 | 说明 |
---|---|---|
Bootstrap ClassLoader(启动类加载器) | JAVA_HOME/jre/lib | 无法直接访问 |
Extension ClassLoader(扩展类加载器) | JAVA_HOME/jre/lib/ext | 上级为 Bootstrap,显示为 null |
Application ClassLoader(应用程序类加载器) | classpath | 上级为 Extension |
自定义类加载器 | 自定义 | 上级为 Application |
类加载器的优先级(由高到低):启动类加载器 -> 扩展类加载器 -> 应用程序类加载器 -> 自定义类加载器。
JAVA_HOME/jre/lib
目录中的,或者被-Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。JAVA_HOME/jre/lib/ext
目录中的,或者被 java.ext.dirs 系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。类加载的过程包括:加载、验证、准备、解析、初始化。其中验证、准备、解析统称为连接。
java.lang.Class
对象。static{}
)中的语句。如图所示:
什么是双亲委派模型?
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
为什么要使用双亲委派模型呢?(好处)
避免重复加载 + 避免核心类篡改
采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父加载器已经加载了该类时,就没有必要子加载器再加载一次。
其次是考虑到安全因素,java 核心 api 中定义类型不会被随意替换,假设通过网络传递一个名为 java.lang.Integer
的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的 java.lang.Integer
,而直接返回已加载过的 Integer.class
,这样便可以防止核心API库被随意篡改。
① 物理地址方面的区别:
② 内存分配方面的区别:
运行期
确认的,因此大小不固定。一般堆大小远远大于虚拟机栈。编译期
就确认,大小是固定的。③ 存放的内容方面的区别:
注:静态变量放在方法区,而静态的对象还是放在堆。
④ 线程共享方面的区别:
参考文章:
总结的面试题也挺费时间的,文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支持一下,后续会亿点点的更新!
为了帮助更多小白从零进阶 Java 工程师,从CSDN官方那边搞来了一套 《Java 工程师学习成长知识图谱》,尺寸 870mm x 560mm
,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,有兴趣的小伙伴可以了解一下,当然,不管怎样博主的文章一直都是免费的~
原文链接:https://blog.csdn.net/weixin_43591980/article/details/117318685
作者:想要飞翔的天使
链接:http://www.javaheidong.com/blog/article/207041/b4c652708b71aa8060e3/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!