Java内存划分

虚拟机底层结构:

  从上往下分为 四层部分:

    【1】类加载器 ClassLoader

      .class 的字节码文件会通过类加载器 ( ClassLoader )加载到 Java虚拟机当中。

    【2】JVM 内存结构 (包括有 方法区、堆、虚拟机栈、程序计数器、本地方法栈)

    【3】执行引擎 (包括有 解释器、即时编译器、垃圾回收)

      解释器: 方法执行时,每行代码是交给 执行引擎的解释器 进行执行

      即时编译器: 方法当中的热点代码(被频繁调用的,被频繁使用的)相关代码 会交给 即时编译器 进行执行。 相当于是对代码优化后执行。

      垃圾回收: 会对堆里面,不再引用的代码,进行回收处理。

    【4】本地方法接口(被调用时使用本地方法栈)

      存在一些底层与操作系统进行交互的代码,主要存在于本地方法接口当中。 通过本地方法接口,调用操作系统相关的方法。

Java的内存划分为5部分

  

  1.虚拟机栈(Stack):存放的都是方法的局部变量,方法运行时一定是在栈中运行

    局部变量:方法的参数,或者是方法{}内部的变量

    作用域:一旦超出作用域,立即从栈中消失

  2.堆(Heap):凡是new出来的东西都在堆内存中

      堆内存里面的东西都有一个地址值:16进制

      堆里面的数据都有默认值,规则:

          如果是整数:默认值为0

          如果是浮点数:默认值为0.0

          如果是字符:默认值为‘\u0000’(空字符)

          如果是布尔:默认值为false

          如果是引用类型:默认值为null

      特点:

        1.堆内存,被线程共享。 需要考虑线程安全问题

        2.堆内存,存在地址值 和 默认值

        3.堆内存,有垃圾回收机制,当 GC 空闲时进行堆内存垃圾回收

  3.方法区(Method Area):存储.class相关信息,包含方法的信息

    方法区在逻辑上是堆的组成部分,是规范,不同的虚拟机实现是不相同的,JVM规范当中,并不做强制要求

      我们常用的虚拟机在jdk1.8以前是采用永久代实现的(堆内存一部分),1.8后采用元空间实现(本地内存、直接内存)

    方法区在虚拟机启动的时候,被创建

    方法区存储类结构相关的信息(成员变量、方法数据、成员方法、构造方法)、运行时常量池

      其中运行时常量池中的 StringTable(串池) 在jdk1.8以前和其他常量一样属于方法区(永久代);1.8后独立出来属于堆(因为StringTable频繁创建销毁,在堆中垃圾回收效率高,不可一起归为元空间),其他常量属于方法区(元空间)

      运行时常量池:

    方法区是线程共享的, 需要考虑线程安全问题

    

  4.本地方法栈(Native Method Stack):专门用于加载 native 修饰的本地方法,主要是与计算机底层硬件进行交互使用

  5.程序计数器(pc Register):与CPU相关,字节码指令执行过程当中,记录下一条指令的执行地址,线程私有,不会存在内存溢出

 栈内存的设置:

  并不是说栈内存设置越大越好,栈内存设置越大,每个线程调用的方法可以更多,也就是栈帧可以更多,但是相应能创建的线程就会减少,因为物理内存是固定的。栈内存采用默认值即可。

  

 堆内存诊断:在测试时可以把堆内存设置小一些,提前暴露出程序存在的问题

  

 

 JVM常见问题解决:https://www.cnblogs.com/roadlandscape/p/12042137.html

 

posted @ 2019-12-17 20:59  糖不甜,盐不咸  阅读(138)  评论(0编辑  收藏  举报