欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JVM---内存结构

程序员文章站 2022-04-18 15:52:28
...

程序计数器

Program Counter Register

  • 是记住下一条JVM指令的执行地址
  • 特点
    是线程私有的
    不会存在内存溢出

虚拟机栈

每个线程运行所需要的内存,成为虚拟机栈
每一个栈是由多个栈帧组成,栈帧是每个方法运行时需要的内存,一个栈帧对应着一个方法调用
每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

垃圾回收是否涉及栈内存?
不会,栈内存是一次次的方法调用产生的栈帧内存,而栈帧内存在方法调用完成后,会自动出栈。
栈内存分配越大越好吗?
通过参数-Xss size参数来指定栈的大小
栈内存如果分配的大,则可以执行的线程数,越来越少,因为物理内存是一定的。
方法内的局部变量是否是线程安全?
局部变量是线程私有的,所以是线程安全的
如果变量是多个共享的,则需要考虑线程安全问题
总结:如果方法内的局部变量没有逃离方法的作用范围,它是线程安全的
如果局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全
(引用作为参数,作为返回值)

/**
 * 局部变量的线程安全问题
 */
public class Demo1_17 {
    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());
    }

//不是线程安全的,StringBuilder作为参数,main线程在修改它,新的线程也在修改,属于线程共享的
    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;
    }
}

栈内存溢(java.lang.*Error)

  • 栈帧过多导致栈内存溢出(方法的递归调用)
  • 栈帧过大导致栈内存溢出(出现情况较少)
  • 第三方库的使用也会导致栈内存溢出(json解析)

线程运行诊断

案例1:cpu占用过多

  • linux中用top定位那个进程对cpu的占用过高
  • ps H -eo pid,tid, %cpu | grep 进程id(ps命令进一步定位是哪个线程引起的cpu占用过高)
  • 使用JDK自带的jstack工具,使用的格式:jstack 进程id,可以根据线程id找到有问题的线程,进一步定位到问题代码的源码行号

案例2:程序运行很长时间没有结果

本地方法栈

给本地方法运行提供内存空间,也是线程私有的

  • 通过new关键字,创建对象都会使用堆内存
  • 它是线程共享的,堆中对象需要考虑线程安全问题
  • 有垃圾回收机制

堆内存溢出问题(java.lang.OutOfMemoryError)

调整堆空间的最大值:-Xmx
排查堆内存问题时,将堆空间调小些

堆内存诊断

jps工具:查看当前系统中有哪些java进程,显示进程编号
jmap工具:查看堆内存占用情况,只能查询某一个时刻进程堆内存占用情况,jmap -head 进程id
jconsole工具:图形界面的,多功能的监测工具(线程,cpu),可以连续监测
jvisualvm工具:图形界面的

方法区

是线程共享的,存储了和类的结构相关的信息,方法区在虚拟机启动时创建,方法区是一个规范,可有不同的实现,JDK1.8之前方法区采用永久代实现,JDK1.8方法区采用元空间来实现

相关标签: JVM