JVM学习笔记———运行时数据区

文章开头,先来探讨一个问题,为什么JAVA的生态圈这么大,它的优势到底在哪里?个人认为,互联网公司选择一门技术,关注的是这门技术是否稳定,是否容易上手,是否方便进行二次开发,是否具有强的移植性。刚入门JAVA的时候,简单的认为面向对象这一编程思想是java语言最大的优势,直到接触到spring,了解了AOP(面向切面编程)的思想,最近又接触了一下JVM,才知晓什么是"坐井观天"。

JAVA有一个大的优势在于:

  • 自动内存管理机制之下,不再需要为没一个new操作去写配对的内存分配和回收等代码, 不容易出现内存泄漏和内存溢出等问题

有人可能会说,不就是内存管理吗,我自己关闭也行,但是随着互联网架构的不断扩大,成百万行代码中又无数个对象,方法。人为控制内存的话一旦出现疏忽,将在生产环境造成灾难性的后果。

下面简要介绍一下JVM的运行时数据区

  • 线程共享数据区:方法区、堆
  • 线程隔离数据区:虚拟机栈、本地方法栈、程序计数器

一,程序计数器

是什么?

  • 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器
  • 线程是一个独立的执行单元,是由CPU控制执行的
  • 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成

有何作用?

  • 为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存

特点?

  • 内存区域中唯一一 个没有规定任何 OutOfMemoryError 情况的区域

个人理解:学过C语言的想必都知道指针,程序技术器就类似于一个个指针存储着各个线程的行号,方便cpu顺序执行指令

二,虚拟机栈

是什么?

用于作用于方法执行的一块Java内存区域

有何作用?

  • 每个方法在执行的同时都会创建一个栈帧(Stack Framel)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程

特点?

  • 局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)以及对象引用(reference 类型)
  • 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常

个人理解:我们先来看一段代码:

import java.util.concurrent.atomic.AtomicInteger;

public class A {

 
    public static void a(){
        System.out.println("enter method a");
    }

    public static void b(){
        a();
        System.out.println("enter method b");
    }

    public static void main(String[] args) {
        b();
        System.out.println("enter method main");
        AtomicInteger atomicInteger = new AtomicInteger(1);
        atomicInteger.compareAndSet(1,2);
    }
}

从这一段简单的代码,不难看出,方法的执行顺序从main函数开始,再执行b方法,再执行a方法,但通过简要分析不难看出,最先执行完的时a方法,其次执行完的是b方法,最后才是main

,最先执行的却最后才执行完成,这种先进后出的数据结构模型想必大家都了解,称之为栈。

三,本地方法栈

  • 是什么?
    • 用于作用域本地方法执行的一块Java内存区域
    • 什么是本地方法?
  • 有何作用?
    • 与Java虚拟机栈相同,每个方法在执行的同时都会创建一个栈帧(Stack Framel)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程
  • 特点?
    • Hotshot将Java虚拟机栈和本地方法栈合二为一

个人理解:稍微解释一下这里的新名词Hotsot,Hotshot是jvm的一种实现方式,大家查看自己java虚拟机型号,至于本地方法栈,把它和虚拟机栈看成一个东西即可

JVM学习笔记———运行时数据区_第1张图片

四,JAVA堆

  • 是什么?
    • 是Java内存区域中一块用来存放对象实例的区域,【几乎所有的对象实例都在这里分配内存】
  • 有何作用?
    • 此内存区域的唯一目的就是存放对象实例
    • Java 堆(Java Heap)是 Java 虚拟机所管理的内存中最大的一块 Java 堆是被所有线程共享的一块内存区域
  • 特点?
    • Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”(Garbage
    • -Xmx -Xms
    • Java堆可以分成新生代和老年代 新生代可分为To Space、From Space、Eden

个人理解:这里是jvm最重要也是最难的一部分,我们平常创建的所有对象实例都在此分配内存,且又所有线程进行共享,垃圾回收(GC)机制也在此产生作用

五,方法区

  • 是什么?
    • 是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
    • 什么是类信息:类版本号、方法、接口
  • 有何作用?
    • 内存中存放类信息、静态变量等数据,属于线程共享的一块区域
    • Hotspot使用永久代来实现方法区 JRockit、IBM J9VM Java堆一样管理这部分内存
  • 特点?
    • 并非数据进入了方法区就如永久代的名字一样“永久”存在了。这区域的内存回收目标主要是针对常量池的回收和对类型的卸载
    • 方法区也会抛出OutofMemoryError,当它无法满足内存分配需求时

个人理解:大家可以直接打开任意一个.class文件,会发现里面都是二进制字节码,这些编译好的二进制文件就交由方法区进行操作,管理。

六,通过一个例子来理解一下以上的内容

public class A {

    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        System.out.println(a==b);
        String c = new String("abc");
        System.out.println(a==c);
        System.out.println(a==c.intern());
    }
}

该程序执行结果是:

         true

         false

         true

下面来简要介绍一下原因:a,b都是运行时常量,而运行时常量池属于方法区的一部分,a,b都是运行时常量,且值相同,即为同一地址,因此比较时相等;而c为一个对象,虽然它的值也是abc,

但对象存储再堆中,因此它不等于a和b; intern方法能将堆中的对象移到方法区中,因此在调用了该方法之后a和c又相等了。

jvm是java程序员的内功,万丈高楼平地起,要想掌握高端的诸如高并发这类技术,jvm必须好好学,个人也是初学jvm,有不足之处还望指出,还可以加好友交流一番。

你可能感兴趣的:(JVM)