• JVM的学习1_____内存模型


             前言:在学习Java第一课时,老师就讲到:Java不同于C/C++的手动内存分配与回收。原来这都得益于JVM的内存自动管理机制,但是在这背后又暗藏什么玄机呢???本人从图书馆借来了《Java虚拟机精讲》来一探究竟。

    一.JVM的内存模型:

    如下图所示可以分为5个模块:堆,栈,本地方法栈,PC寄存器,方法区。

    这些内存区域用来存储程序运行时的数据。

    根据线程访问的权限不同,其中线程共享的内存区域:堆,方法区,运行时常量池;线程私有的内存区域:栈,本地方法栈,PC寄存器。

    1.线程共享的内存区域(堆区,方法区,运行时常量池):

    1.堆(heap): 

          在JVM启动的时候创建该区域,堆区在实际的物理内存中是可以不连续的。我们程序中所创建的对象实例,和数组都存放在堆区,所以堆区是GC(垃圾回收器)的高频工作地点,但是当回收和使用大的内存区域时,可能会出现性能瓶颈,这时我们就提出疑问对象一定要放在堆区吗???当然是可以不放在堆区。对此我们有两套解决方案:逃逸分析,栈上分配以及TaoBaoVM都是可以将对象放在堆区之外的解决方案,用来提升GC的效率。

          由于Java中对象的生命周期不同,有的对象生命周期非常短暂,有的对象声明周期甚至和JVM的生命周期一样,这就使得要采用不同的GC算法来收集不同类型的对象。由此分代回收算法诞生!目前几乎所有的GC算法都是分代收集算法。

          堆区的内存区域又可细分为:新生代(Young Gen),年老代(Old Gen)其中新生代又可按8:1:1分为Eden,FromSurvivor,ToSurvivor。堆区的参数设置大小在JVM启动的时候就已经设置好了,可以通过 -Xms:获得堆区的起始大小; -Xmx:获得堆区的最大大小。当超出-Xmx(堆区的最大值)就会抛出OOM(out of memory)Error。

    //一个OOM的代码实例
    public class OOMTest {
        public static void main(String [] args){
            List<OOMObject> list=new ArrayList<>();
            while (true){
                list.add(new OOMObject());
                System.out.println("创建了一个静态对象!");
            }
        }
        static class  OOMObject{
    
        }
    }

    2.方法区:

           方法区和堆区是一样的,也是属于线程共享的区域。方法区中存储了每一个Java类的结构信息,比如:运行时常量池,字段,方法数据,以及构造函数和普通方法的字节码内容,和类,实例,接口初始化时所用到的特殊方法等数据。在HotSpot(是sunJDK,openJDK所带的JVM,也是目前使用最广的Java虚拟机)的实现中方法区的实际的物理内存位于堆中,也就是说方法区只是逻辑上的独立。

          方法区也被称为永久代,因为方法区并不会象堆区那样进行频繁的GC,甚至还可以设置参数让GC不回收方法区,若GC收集方法时也只是收集运行时常量池和类型卸载。方法区可通过-XX:MaxPermSize设置内存大小进行动态内存扩展。

         方法区也会发生内存溢出,当内存大小超过-XX:MaxPermSize时就会抛出OOMError。

    3.运行时常量池:

         运行时常量池属于方法区,一个有效的字节码文件中除了包含字段,方法,接口等信息外,还应包括常量池表,运行时常量池就是常量池表运行时的表示形式,运行时常量池中可以存放多种不同的常量。

        当类加载器成功的将一个类或者接口加载进JVM,就会分配相应的运行时常量池,由于运行时常量池位于方法区中,故也会发生OOMError

    2.线程私有的内存区域(PC寄存器,栈,本地方法栈):

    1.pc寄存器:

         pc寄存器不同于物理寄存器,更像是一个pc计数器,其生命周期和线程的生命周期保持一致。PC寄存器记录了当前字节码指令地址;

         pc寄存器是唯一一个不会发生OOMError的内存区域。

    2.Java栈:

         栈区的生命周期和线程的生命周期一样,栈主要用来存储栈帧,栈帧中存储了局部变量表,操作数栈,以及方法出口等信息。Java堆中存的是对象实例,那么Java栈的局部变量表中存放的是各类原始数据类型,对象引用,以及returnAddress(是JVM内部的原始数据类型)类型。

        Java栈的大小,可以设置为固定大小,也可设置为动态的大小。当线程请求分配的栈容量超过Java栈的最大大小JVM就会抛出StackOverflowError异常。

    3.本地方法栈:

        用于支持本地方法的执行,并不是必须要的一块内存区域。同样也会发生OOM和StackOverFlow。

  • 相关阅读:
    Mysql 视图用途、使用场景、性能问题及使用注意事项
    深入解析MySQL视图VIEW
    delete语句的基本用法
    update语句基本用法
    mysql插入中文数据变成问号怎么处理
    MySQL数据表中有自增长主键时如何插入数据
    INSERT INTO语句的基本用法
    mysql HAVING用法
    mysql关于group by的用法
    python模拟鼠标拖动教程
  • 原文地址:https://www.cnblogs.com/xbfchder/p/11391585.html
Copyright © 2020-2023  润新知