ITPub博客

首页 > 应用开发 > Java > JVM的特性,通过代码来揭秘运行时数据区

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

原创 Java 作者:程序员的成长之路 时间:2018-11-29 11:22:31 0 删除 编辑

运行时数据区

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


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

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

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

而黄色区,会被称为栈。

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

先上一段代码:

/**  * 作者: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();    }  }
后面的分析都是建立在这个AppTest类的。

堆:

堆是用来干嘛的?


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

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

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

/**  * 作者: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);    } }

启动参数设置为:-Xms64m -Xmx128m,然后运行:


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

方法区:

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


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


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

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

比如:

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

常量:final .....

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

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

JIT编译:就是运行编译。

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

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


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

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

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

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

程序计数器:

什么是程序计数器?


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

栈:

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


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

/**  * 作者: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);    }  }
执行一下:



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

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

所以栈和程序运行有关:


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

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


局部变量表又是什么?


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

那为什么又要压栈呢?

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

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

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

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

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


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

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


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

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


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



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

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69900357/viewspace-2222087/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2018-11-28

  • 博文量
    6
  • 访问量
    5360