前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >初识java虚拟机(JVM)运行时数据区结构

初识java虚拟机(JVM)运行时数据区结构

作者头像
zhanyd
发布2022-05-16 13:22:51
1960
发布2022-05-16 13:22:51
举报
文章被收录于专栏:编程我也会

java虚拟机(JVM)是java平台的基石,任何java程序都是在JVM上运行的。

java编译器把java程序编译成class文件,然后把class文件载入JVM中运行,JVM屏蔽了底层的硬件。

所有的class文件只在JVM中运行,实现了一次编写到处运行(Write Once Run Anywhere)的宏伟目标。

JVM内部结构包括:

  1. 类加载子系统
  2. 运行时数据区
  3. 执行引擎

本文只介绍运行时数据区的结构。

JVM运行时数据区结构
  • 方法区 虚拟机共享的数据区,每个虚拟机只有一个方法区。 主要存储已被虚拟机加载的类的信息、常量、静态变量等数据。
  • 堆区

虚拟机共享的数据区,每个虚拟机只有一个堆区。

java 堆是虚拟机管理的内存中最大的一块区域,存储所有的对象实例以及数组。

由于堆区是多线程共享的,所以不是线程安全的。

  • 栈区

每个线程都有自己独立的栈区,栈区是线程安全的,是java方法执行的内存模型。

每个方法在执行时都会创建一个栈帧(stack frame)用于存储本地变变量表、操作数栈、帧数据等。

随着方法调用的结束,相应的栈帧数据也随之删除。

  • 程序计数器

每个线程都有自己独立的程序计数器,指向当前指令的地址。

  • 本地方法栈

每个线程都有自己独立的本地方法栈,用于存储调用本地方法(native method)的信息。

下面我们来验证一下,对象是不是存在堆区的,方法调用相关的数据是不是存在栈区的。

堆区溢出

java堆用于存储对象实例,只要不断的创建对象,并保证避免垃圾回收机制清除这些对象,在达到最大堆容量限制的时候就会产生内存溢出异常。

-Xmx10m参数表示把堆区的最大容量变小调成10M,

-XX:+HeapDumpOnOutOfMemoryError参数表示生成堆区快照文件。

vm 参数:

-Xmx10m

-XX:+HeapDumpOnOutOfMemoryError

代码语言:javascript
复制
import java.util.ArrayList;
import java.util.List;

/**
 * vm args: -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list  = new ArrayList<>();
        while(true) {
            list.add(new OOMObject());
        }
    }
}
输出结果:

第一行 java.lang.OutOfMemoryError: Java heap space 表示java堆区空间溢出,说明了对象是存储在堆区中的。

代码语言:javascript
复制
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10876.hprof ...
Heap dump file created [13387910 bytes in 0.036 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  at java.util.Arrays.copyOf(Arrays.java:3210)
  at java.util.Arrays.copyOf(Arrays.java:3181)
  at java.util.ArrayList.grow(ArrayList.java:261)
  at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
  at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
  at java.util.ArrayList.add(ArrayList.java:458)
  at jvm.HeapOOM.main(HeapOOM.java:17)

在项目的路径下会生成 java_pid10876.hprof 文件,这个文件就是dump出来的堆转储快照文件。我们用Memory Analyzer打开看一下。

点击上图最下面的details链接可以看到更详细的信息:

可以看到OOMObject对象占了93%的内存,罪魁祸首就是它了。

栈区溢出

每个方法在执行时都会创建一个栈帧,

-Xss160k参数表示栈区的容量为160k,然后递归调用方法,让栈区溢出。

vm 参数:-Xss160k

代码语言:javascript
复制
/**
 * vm args: -Xss160k
 */
public class JavaVMStackSOF {

    static int stackLength = 1;

    /**
     * 递归调用,使其超出栈的最大深度
     */
    public void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {

        JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();
        try{
            javaVMStackSOF.stackLeak();
        }catch (Throwable e) {
            System.out.println("stack length: " + stackLength);
            throw e;
        }
    }
}
输出结果:

Exception in thread “main”

java.lang.StackOverflowError 表示java栈区空间溢出,说明了方法调用是存储在栈区中的。

代码语言:javascript
复制
stack length: 772
Exception in thread "main" java.lang.StackOverflowError
    at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
    at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
    at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
    at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
    at JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
    ......

了解了一些JVM的知识对我们平时编程还是很有用的哦,

比如看到java.lang.OutOfMemoryError: Java heap space 异常就知道是堆区溢出了,可能是对象创建太多了;

看到java.lang.StackOverflowError异常就知道是栈区溢出了,马上去查查是不是方法调用有问题。

这样定位问题是不是更精准了呢?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程我也会 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JVM运行时数据区结构
  • 堆区溢出
  • 输出结果:
  • 栈区溢出
  • 输出结果:
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档