【JVM】JVM01(概述-程序计数器-栈-堆)

🎄如果文章对大家有帮助,欢迎点赞👍收藏⭐️评论📝支持,小温在这里谢过大家了,在这里祝福大家新年快乐!🎄

笔记整理于传智播客黑马程序员-jvm小滴课堂,老师讲的细致易懂

在这里插入图片描述

文章目录

  • ⭐️1.JVM入门

    • ⭐️1.1 jvm定义
  • ⭐️1.2 jvm优势

  • ⭐️1.3 JVM,JRE,JDK的比较

  • JVM运行时数据区

  • 常见的JVM

  • ⭐️2.Program Counter Register 程序计数器(寄存器)

  • ⭐️3.Java Virtual Machine Stacks(java虚拟机栈)

    • 栈演示
  • ⭐️面试题

    • ⭐️4.栈内存溢出
  • ⭐️本地方法栈

  • ⭐️5.堆

    • 堆内存溢出问题
  • 堆内存诊断


⭐️1.JVM入门

=======================================================================

⭐️1.1 jvm定义


Java Virtual Machine - java程序的运行环境(java二进制字节码的运行环境)

⭐️1.2 jvm优势


  • 一次编写,到处运行的基石

  • 自动内存管理,垃圾回收机制

java语言出现时机比较早,同一时期它的竞争对手是c和c++,而c和c++是没有垃圾回收功能的,需要程序员自己

释放内存,如果编码不当,很容易造成内存的泄漏,java虚拟机的垃圾回收功能减少了程序员的负担

  • 数组下标越界检查

  • 多态

⭐️1.3 JVM,JRE,JDK的比较


在这里插入图片描述

JVM运行时数据区


在这里插入图片描述

在这里插入图片描述

常见的JVM


在这里插入图片描述

⭐️2.Program Counter Register 程序计数器(寄存器)

=====================================================================================================

程序计数器在jvm中的位置

在这里插入图片描述

程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器

字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令分支循环跳转异常处理线程恢复等基础功能都需要依赖这个计数器来完成

在这里插入图片描述

程序计数器

作用:

记住下一条jvm指令的执行地址

特点:

1.是线程私有的

每个线程都有自己的程序计数器线程切换执行的过程中,为了准确知道指令执行到哪里,需要程序计数器发功

在这里插入图片描述

2.不会存在内存溢出(堆栈等都会出现内存溢出)

在这里插入图片描述

⭐️3.Java Virtual Machine Stacks(java虚拟机栈)

=======================================================================================================

java虚拟机栈是作用于方法执行的一块java内存区域

栈在jvm中的位置

在这里插入图片描述

栈区

  1. 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中

  2. 每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。

  3. 栈分为3个部分:基本类型变量区执行环境上下文操作指令区(存放操作指令).

  • 每个线程运行时所需要的内存,称为虚拟机栈

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存,方法内有参数,局部变量,返回地址等

  • 都需要占用内存

  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

在这里插入图片描述

栈帧:每个方法运行时需要的内存

当调用第一个方法时,栈就给第一个方法划分栈帧空间,并且把它压入栈内,当方法执行完毕,方法对应的栈帧出栈,释放方法所占用的内存

栈演示


package day01;

/**

  • Description

  • User:

  • Date:

  • Time:

*/

public class StackTest {

public static void main(String[] args) {

method1();

}

private static void method1(){

method2(1,2);

}

private static int method2(int a,int b){

int c = a+b;

return c;

}

}

首先执行method1,method1对应的栈帧入栈,称为活动栈帧

在这里插入图片描述

继续执行,method1调用method2,method2对应的栈帧入栈,成为活动栈帧

在这里插入图片描述

method2执行完毕,method2对应的栈帧被释放掉,method1方法对应的栈帧称为活动栈帧

在这里插入图片描述

最后method1执行完毕,main方法对应的栈成为活动栈帧,当main方法执行完毕出栈,虚拟机栈空,方法全部结束

⭐️面试题

===================================================================

1.垃圾回收机制是否涉及栈内存?

不涉及,栈内存涉及的是一次一次的方法调用所产生的栈帧内存,而栈帧内存在每一次的方法调用后都会被弹出栈,被自动回收掉,所以不需要垃圾回收来管理栈内存,垃圾回收主要回收堆内存中的无用对象

2.栈内存分配越大越好吗?

栈内存可以通过虚拟机参数来进行指定 -Xss size

操作系统的栈默认大小在这里插入图片描述

我们物理内存的大小是一定的,如果我们栈内存分的大,则线程数会变少,加入我们一个线程所用1兆内存,物理内存假设有500兆,我们理论上可以有500个线程同时运行,但如果设置每个线程的栈内存为2兆,那么理论上我们只能同时运行250个线程,线程数变少

故栈内存不是越大越好,栈内存大只是能够进行更多次的方法递归调用,而不会增强运行的效率,反而会导致线程数目的变少

3.方法内的局部变量是否线程安全?

我们举个例子

int x = 0;

for (int i=0;i<5000;i++){

x++;

}

System.out.println(x);

当多个线程同时执行该方法,上面代码会不会造成x值的混乱?

不会,x变量是方法内的局部变量,一个线程对应一个栈,线程内每次方法调用都会产生新的栈帧

在这里插入图片描述

可以看到,在每个线程都有自己私有的一个x变量,运行时互不干扰,如果执行上述方法,会同时+5000

但是当我们把x改为静态变量,结果就会不一样,static修饰的变量为两个方法所共享,并不私有

在这里插入图片描述

线程执行x++后,每次自增都会将结果写回静态区,如果不加线程保护,就会产生线程安全的问题

我们再看一个案例

package day01;

/**

  • Description

  • User:

  • Date:

  • Time:

*/

public class ThreadDemo {

public static void main(String[] args) {

}

public static void 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.append(1);

sb.append(2);

sb.append(3);

System.out.println(sb.toString());

}

public static StringBuilder m3(){

StringBuilder sb = new StringBuilder();

sb.append(1);

sb.append(2);

sb.append(3);

return sb;

}

}

m1方法不会出现线程安全问题,因为StringBuilder sb是我们方法内的一个局部变量,是私有的,其他线程不可能同时访问到该对象

m2方法不是线程安全的,因为StringBuilder sb是作为方法参数传入,有可能有其他的线程可以访问到它,它对其他线程是共享的

m3方法也不是线程安全的,StringBuilder sb虽然是方法内的局部变量,但是他作为一个方法的结果返回,便逃离了m3对它的作用范围

因此我们得出结论

- 如果方法内的局部变量没有逃离方法的作用范围,它就是线程安全的

- 如果局部变量引用了对象并逃离了方法的作用范围,他就是非线程安全的,如果是(int ,float,double)等非引用对象,即使逃离了方法的作用范围,也是线程安全的

在这里插入图片描述

⭐️4.栈内存溢出


1.栈帧过多导致栈内存溢出,例如方法递归调用没有结束标志

在这里插入图片描述

2.栈帧过大导致栈内存溢出

在这里插入图片描述

下面我们结合两个具体的案例来看栈溢出的几个场景

public class StackDemo01 {

private static int count;

public static void main(String[] args) {

try {

method1();

}catch (Throwable e){

e.printStackTrace();

System.out.println(count);

}

}

private static void method1(){

count++;

method1();

}

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例

MyBatis答案解析
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

大家看完有什么不懂的可以在下方留言讨论也可以关注。

觉得文章对你有帮助的话记得关注我点个赞支持一下!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
a开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例
[外链图片转存中…(img-bhzb5wQl-1713397233551)]

[外链图片转存中…(img-zbDgE4qK-1713397233551)]
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

大家看完有什么不懂的可以在下方留言讨论也可以关注。

觉得文章对你有帮助的话记得关注我点个赞支持一下!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值