前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM的特性,通过代码来揭秘运行时数据区

JVM的特性,通过代码来揭秘运行时数据区

作者头像
良月柒
发布2019-03-20 15:46:36
3610
发布2019-03-20 15:46:36
举报
文章被收录于专栏:程序员的成长之路

技术文章第一时间送达!

运行时数据区

之前学习类加载器的时候,最后放出了一张图,再来回顾一下

类加载器就是把字节码文件加载到运行时数据区里面的一个机制,加载到运行时数据区之后呢,又发生了什么?

接下来我们就来看看。这就是JVM运行时数据区:

运行时数据区分为:方法去、堆、虚拟机栈、本地方法栈、程序计数器。

而黄色区,会被称为栈。

堆和栈的根本作用,就是用来存放数据用的。

先上一段代码:

代码语言:javascript
复制
/**
 * 作者:LKP
 * 时间:2018/11/7
 */
class Person{
    String name = new String("1234");    
      public Person(String name) {        
          this.name = name;
    }    
      public void sayHello(){
        System.out.println("hello:"+name);
    }
}
public class AppTest {    
    public static void main(String[] args) {
       Person person = new Person("张三");
       person.sayHello();
   }

}
代码语言:javascript
复制
后面的分析都是建立在这个AppTest类的。

堆:

堆是用来干嘛的?

就好比前面的程序,new Person("张三"); 它存储的地方就是在堆里面。

什么是OutOfMemoryError异常,可能有些人没有接触过,我也是再一次面试当中遇到的,之后去查阅过相关资料。

现在我们来模拟一下OutOfMemoryError异常:

代码语言:javascript
复制
/**
 * 作者:LKP
 * 时间:2018/11/7
 */
public class HeapOOM {    
   //-Xms64m -Xmx128m
   public static void main(String[] args) {
       String[] str = new String[400000000];
       System.out.println(str.length);
   }
}
代码语言:javascript
复制
启动参数设置为:-Xms64m -Xmx128m,然后运行:

这种异常就是OutOfMemoryError异常,内存溢出了,造成的原因很多种,有兴趣的小伙伴可以去了解一下。

方法区:

之前说到了类加载加载,并且执行,我们怎么样执行呢?这就跟方法区有关系了。

类信息:它是对一个类的描述

上面两条sql语句一样,第一条是它的表结构,这些就是表结构的信息。类信息(MetaInfo)就是元数据,描述我们一个类的信息的。

运行时常量池:它的作用是存放我们一些常量和静态变量的

比如:

静态变量:static int NAME = "张三";

常量:final .....

这些都是存放在运行时常量池的。

编译器有两个:一个是静态编译,一个是JIT。

JIT编译:就是运行编译。

静态编译:java编译成class文件

为什么要有JIT编译呢?那肯定是有它好处的:

看一下这段代码,他是热点代码,就是需要频繁去执行的

为了效率,JIT编译会把字节码编译为机器执行码,这样速度就大大提高了。

JIT的目的,就是把字节码>>>机器执行码,把它存放在方法区里面。

方法区呢,就是存放方法的地方,不过为了区分不同类的方法,也需要把类信息也存储进去,这样才能区分不同类的相同方法。

程序计数器:

什么是程序计数器?

程序计数器它就是让我们程序按照我们的指定指令执行的步骤,我们的步骤放到一个区域里面,程序计数器就按照第一步干什么,第二步干什么来执行。

栈:

什么是栈呢?先看看这张图

为了更好的进行理解,我们先来写个递归:

代码语言:javascript
复制
/**
 * 作者:LKP
 * 时间:2018/11/8
 */
public class Digui {    
    private Long i = 0l;    
    public void test(int a, double d) {
       i++;
       System.out.println("=====>" + i);
       test(a, d);
   }    
    public static void main(String[] args) {
       Digui app = new Digui();
       app.test(0, 0.0d);
   }

}
代码语言:javascript
复制
执行一下:

报错了(StackOverflowError)。为什么报错呢?

StackOverflowError异常代表的是,当栈深度超过虚拟机分配给线程的栈大小时就会出现此error。

所以栈和程序运行有关:

栈概念:先进后去的原则,刚刚出现StackOverflowError的异常,证明栈是有数量限制的。

每个栈帧里面存储的又是什么呢?

局部变量表又是什么?

main函数一般都是主线程,步骤1产生的就是局部变量表。

那为什么又要压栈呢?

看一下步骤2,因为当运行main线程的时候,add线程还没有产生。当运行add的时候会把它放在main上面,为什么这样,这就和等下弹栈有关系了。

步骤2返回C就是最关键的,它就是弹栈过程,弹出的这个数据机构(add线程)就消失了,什么都没有了,包括局部变量什么的。

步骤3是返回到main线程去了。

为什么用栈不用队列呢?原因很简答,因为弹栈压栈都是最简单的,而队列则需要去查找。

来看看JVM中堆、栈和方法区这三者的联系。

局部变量表可以存放八大数据基本类型,再加上一种引用reference(引用就是一个地址,指向堆、常量池的地址)

回顾一开始出现的程序,结合来理解这三者的关系。

看完这篇文章,相信你对数据运行区的了解加深了很多。

最后再来看一下JVM内存区域:

1.8 永久代已经废掉了,直接使用内存,不过多阐述,有兴趣可自行去了解。

有什么错误,或者用词不当还希望大家留言。

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

本文分享自 程序员的成长之路 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 运行时数据区
    • 堆:
      • 方法区:
        • 程序计数器:
          • 栈:
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档