JVM的内存结构

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈
  • 方法区

程序计数器

二进制字节码-->解释器-->机器码-->CPU

作用

记录下一条JVM指令的执行地址

特点

  • 线程私有的(每个线程有自己的程序计数器):java支持多线程运行,CPU给每个线程分配一个时间片,如果在时间片内没运行完,去执行另一个线程在执行该程序。线程切换的过程中,将记录线程一应该执行的下一条代码
  • 不会存在内存溢出

虚拟机参数

-Xss+内存大小

特点

先进后出(例如:手枪弹夹,羽毛球桶)

定义

  • 虚拟机栈:每个线程运行需要的内存空间
  • 栈帧: 每个方法运行时需要的内存
  • 每个线程由多个栈帧做成,对应着方法调用时占用的内存(方法内调用别的方法)

  • 每个线程只能有一个活动栈帧,对应着当前正在执行的方法
    JVM——DAY1(程序计数器,栈,堆)-小白菜博客
    执行完对应的方法后,栈帧出栈,将对应的内存释放掉

问题辨析

  • 垃圾回收是否涉及栈内存?
    不需要,方法(栈帧)在执行后会被自动弹出栈

  • 栈内存分配越大越好吗?
    不是,栈内存越大,线程越少(机械内存固定10M,一个栈2M则可以运行5个线程;一个栈1M,则可运行10个线程)

  • 方法内的局部变量是否安全?(多个线程对这个变量是共享的还是这个变量对每个线程是私有的)

不会,每个线程各有一个栈,各自的栈里各有一个栈帧存储x,互不干扰。

如果方法内局部变量没有逃离方法的作用访问,他是线程安全的
如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

内存溢出

  • 栈帧过多导致栈内存溢出(递归死循环)
  • 栈帧过大(不太容易出现)

线程诊断

  • 案例一:CPU占用过多(需要Linux操作系统)
  1. 用top定位哪个进程对cpu的占用过高
  2. ps H -eo pid,tid,%cpu|grep进程id(用ps命令进一步定位哪个线程引起cpu占用过多)
  3. jstack进程(可以根据线程id找到有问题的线程,进一步定位问题代码的源码行号)
  • 案例二: 程序运行很长时间没有结果(需要Linux操作系统)

本地方法栈

在调用本地方法是提供的内存空间(本地方法:不是由java代码编写的方法,Java代码的限制,底层的代码需要c/c++实现的本地方法。如:object类的clone()方法)

虚拟机参数

-Xmx+内存大小

Heap堆

通过new关键字,常见对象都会使用堆内存

特点

  • 它是线程共享的,堆中对象都需要考虑线程安全性问题
  • 有垃圾回收机制

堆内存溢出

String a = "hello";
List<String> list = new ArrayList<>();
while(true){
  list.add(a);
  a = a + a;
}

list:hello / hellohello / hellohellohello...

堆内存诊断

  • jps工具:查看当前系统中有哪些java进程
  • jmap工具:查看堆内存占用情况
public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("1....");
        Thread.sleep(30000);
        byte[] array = new byte[1024 * 1024 * 10];
        System.out.println("2....");
        Thread.sleep(30000);
        array = null;
        System.gc();
        System.out.println("3....");
        Thread.sleep(1000000L);
    }
}

运行以上代码打开控制台选择Terminl(命令行界面)
在“1...”打印出后输入jps
在“2...”打印出后输入jhsdb(看jdk,有的不需要) jmap -heap 45984(你运行的程序前面的代号)
在“3...”打印出后输入jhsdb(看jdk,有的不需要) jmap -heap 45984(你运行的程序前面的代号)
观察比较堆内存的使用情况

  • jconsole工具:图形界面的多功能监测工具,可以连续监测

运行以上代码打开控制台选择Terminl(命令行界面)输入jconsole,回车会跳出Java监控和管理控制台,选择你运行的程序连接-->不安全的;连接观察内存占用情况

案例

  • 垃圾回收后,内存占用仍然很高
    使用jvirsualvm(可视化的形式展示虚拟机,在控制台使用)