JVM 简介、程序计数器、虚拟机栈

JVM是什么?

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

Java的优点(JVM)

  • 一次编写,到处运行
  • 自动内存管理,垃圾回收功能
  • 数组下标越界越界检查
  • 多态
JVM JDK JRE 的关系

在这里插入图片描述
Program Counter Register程序计数器(寄存器)

在java代码进行编译执行的时候,先将java代码转换成二进制的编码,这个地方的二进制编码就是jvm指令,jvm的指令会给到解释器,而在这里程序计数器就会记住吓一跳jvm指令的地址。这就是程序计数器。

程序计数器的特点

  • 是线程私有的
  • 不会存在内存溢出

在这里插入图片描述
Java Virtual Machine Stack 虚拟机栈

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

使用代码进行测试,代码如下:一段简单的java代码,在设置断点,进行debug,每执行一条语句,这个方法会占用内存,也就是会被放进这个栈当中,当方法执行完成之后再进行出栈操作。

在这里插入图片描述
问题辨析

  1. 垃圾回收是否涉及栈内存?
    答:栈的内存不需要进行回收。
  2. 栈内存分配越大越好吗?
    答:不是,内存分配的越大,线程的数目会变少,采取默认大小即可。
  3. 方法内的局部变量是否线程安全?
    答:如果方法内局部变量没有逃离方法的作用访问,它是线程安全的。如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全。

在第三个问题当中,使用以下代码进行测试:其中只有第一个方法时线程安全的。方法二由于有值进行传递进来,不能确保线程是安全的。第三个方法由于有返回值所以线程也是不安全的。

public class thread_security {
	public static void main(String[] args) {
		StringBuilder sb = new StringBuilder();
		sb.append(4);
		sb.append(5);
		sb.append(6);
		new Thread(() -> {
			m2(sb);
		}).start();
	}

	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;
	}
}

栈内存溢出

容易导致栈内存溢出出现的情况

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

通过以下代码演示栈内存溢出这种情况,代码当中在一致调用method1这个方法,每次调用后栈帧会加一,但是没有设置出栈,最后肯定会导致栈内存溢出,出现报错,在这里设置一个静态变量count进行记录,调用多少次之后才会溢出。

public class stack_overflow {
	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();
	}
}

运行代码出现报错:java.lang.StackOverflowError 栈内存溢出。大概在2w多次将会溢出

在这里插入图片描述
在这里我们可以设置栈的大小,查看调用次数和大小是否有关,在eclipse当中,右键单击代码编辑区,选择Run As 下的run configurations,如下图:

在这里插入图片描述
再次运行代码,可以发现,运行次数很显然变少了,可以得出,栈的内存大小和溢出有关

在这里插入图片描述
线程运行诊断

案例:一个应用占据的cpu过高,

  1. 在linux系統下,使用top命令进行定位,定位到哪个进程对cpu占用过高。使用 ps H -eo pid,tid,%cpu | grep 进程id (用ps命令进一步定位是哪个线程引起的cpu占用过高)。使用 jstack 进程id 可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Modify_QmQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值