Java 虚拟机篇
简述JVM内存模型
线程私有的运行时数据区: 程序计数器、Java 虚拟机栈、本地方法栈。
线程共享的运行时数据区:Java 堆、方法区。
简述程序计数器
程序计数器表示当前线程所执行的字节码的行号指示器。
程序计数器不会产生StackOverflowError和OutOfMemoryError。
简述虚拟机栈
Java 虚拟机栈用来描述 Java 方法执行的内存模型。线程创建时就会分配一个栈空间,线程结束后栈空间被回收。
栈中元素用于支持虚拟机进行方法调用,每个方法在执行时都会创建一个栈帧存储方法的局部变量表、操作栈、动态链接和返回地址等信息。
虚拟机栈会产生两类异常:
- StackOverflowError:线程请求的栈深度大于虚拟机允许的深度抛出。
- OutOfMemoryError:如果 JVM 栈容量可以动态扩展,虚拟机栈占用内存超出抛出。
简述本地方法栈
本地方法栈与虚拟机栈作用相似,不同的是虚拟机栈为虚拟机执行 Java 方法服务,本地方法栈为本地方法服务。可以将虚拟机栈看作普通的java函数对应的内存模型,本地方法栈看作由native关键词修饰的函数对应的内存模型。
本地方法栈会产生两类异常:
- StackOverflowError:线程请求的栈深度大于虚拟机允许的深度抛出。
- OutOfMemoryError:如果 JVM 栈容量可以动态扩展,虚拟机栈占用内存超出抛出。
简述JVM中的堆
堆主要作用是存放对象实例,Java 里几乎所有对象实例都在堆上分配内存,堆也是内存管理中最大的一块。Java的垃圾回收主要就是针对堆这一区域进行。可通过 -Xms 和 -Xmx 设置堆的最小和最大容量。
堆会抛出 OutOfMemoryError异常。
简述方法区
方法区用于存储被虚拟机加载的类信息、常量、静态变量等数据。
JDK6之前使用永久代实现方法区,容易内存溢出。JDK7 把放在永久代的字符串常量池、静态变量等移出,JDK8 中抛弃永久代,改用在本地内存中实现的元空间来实现方法区,把 JDK 7 中永久代内容移到元空间。
方法区会抛出 OutOfMemoryError异常。
简述运行时常量池
运行时常量池存放常量池表,用于存放编译器生成的各种字面量与符号引用。一般除了保存 Class 文件中描述的符号引用外,还会把符号引用翻译的直接引用也存储在运行时常量池。除此之外,也会存放字符串基本类型。
JDK8之前,放在方法区,大小受限于方法区。JDK8将运行时常量池存放堆中。
简述直接内存
直接内存也称为堆外内存,就是把内存对象分配在JVM堆外的内存区域。这部分内存不是虚拟机管理,而是由操作系统来管理。Java通过DriectByteBuffer对其进行操作,避免了在 Java 堆和 Native堆来回复制数据。
简述Java创建对象的过程
- 检查该指令的参数能否在常量池中定位到一个类的符号引用,并检查引用代表的类是否已被加载、解析和初始化,如果没有就先执行类加载。
- 通过检查通过后虚拟机将为新生对象分配内存。
- 完成内存分配后虚拟机将成员变量设为零值
- 设置对象头,包括哈希码、GC 信息、锁信息、对象所属类的类元信息等。
- 执行 init 方法,初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。
这里聊一下我对八股文的一些看法吧。
记得之前有个读者在评论区贴出来了这么一段话。
现在背八股文也好,小学时候背课文也罢,都是我们生活的一部分,但想成功,就别嫌自己笨,去掉所有疑问,我不能站在原地等,把握每一秒,每天只有1440分,我不用戴项链,但要保持纯真,我只需要在梦想上永远保持恒温,放低身份,不计成本,每一步都走得沉稳,就算是身无分文,还被人说是新一代的能民工,也驰骋疆场攻破城门,比起天赋过人,我更像是个笨学生,但我明白一个道理,铁杵也能磨成针。
这段话的出处我不记得了,但有一说一,讲得真好,再给我两天时间,我就背会了,哈哈哈。
科举考试的时候,学子们对八股文很反感,很多浪漫的诗人甚至不屑于参加科举。
放到现在,仍然是这样子,很多人面对一条条的面试题,尤其是有固定答案的,简直不要太讨厌。
但八股文真的没用吗?
不,还是有用的,这些东西背会了,在脑海中存储着,等的就是有朝一日能用得上。
而这一天早晚会来到,因为现实场景中,遇到的很多问题都是需要理论支撑的,而八股文就是理论,底层的原理都囊括进来了。
再者,还是那句话,面试的时候,面试官问你了,你能答出来就是能力,答不出来就白搭。
垃圾收集算法,volatile 关键字、synchronized 关键字这些,你不背下来,面试的时候肯定会吃亏。
在我看来,八股文肯定是有用的,但面试能不能过,有些人如果完全不去理解,背了八股可能也不会过,还是自己要在八股文的基础上去理解下。