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

朴灿烈づ我的快乐病毒、 2022-12-15 11:22 260阅读 0赞

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. 方法内的局部变量是否线程安全?
    答:如果方法内局部变量没有逃离方法的作用访问,它是线程安全的。如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全。

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

  1. public class thread_security {
  2. public static void main(String[] args) {
  3. StringBuilder sb = new StringBuilder();
  4. sb.append(4);
  5. sb.append(5);
  6. sb.append(6);
  7. new Thread(() -> {
  8. m2(sb);
  9. }).start();
  10. }
  11. public static void m1() {
  12. StringBuilder sb = new StringBuilder();
  13. sb.append(1);
  14. sb.append(2);
  15. sb.append(3);
  16. System.out.println(sb.toString());
  17. }
  18. public static void m2(StringBuilder sb) {
  19. sb.append(1);
  20. sb.append(2);
  21. sb.append(3);
  22. System.out.println(sb.toString());
  23. }
  24. public static StringBuilder m3() {
  25. StringBuilder sb = new StringBuilder();
  26. sb.append(1);
  27. sb.append(2);
  28. sb.append(3);
  29. return sb;
  30. }
  31. }

栈内存溢出

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

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

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

  1. public class stack_overflow {
  2. private static int count;
  3. public static void main(String[] args) {
  4. try {
  5. method1();
  6. } catch (Throwable e) {
  7. e.printStackTrace();
  8. System.out.println(count);
  9. }
  10. }
  11. private static void method1() {
  12. count++;
  13. method1();
  14. }
  15. }

运行代码出现报错: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 条评论,260人围观)

还没有评论,来说两句吧...

相关阅读

    相关 jvm 虚拟

    JVM虚拟机栈是每个线程都拥有的内存区域,用于执行方法调用。在源码层面,虚拟机栈由复杂的C++实现控制,与Java开发者的日常工作关联不大。但是,理解虚拟机栈如何工作有助...