zoukankan      html  css  js  c++  java
  • JVM之内存模型

    一、JVM内存区域介绍

      

        两张图均以《深入理解java虚拟机》为参考制作的,第一张图对java内存进行区域上的划分,第二张图主要是从运行的角度对栈做出进一步的说明

        由第二张图可以更深入的理解线程私有的含义,虚拟机栈并不是一整块区域,而是由众多的运行的线程组成

    二、名词解释

      Java堆

        在虚拟机启动时创建,此内存区域唯一目的就是存放对象实例,几乎所有的对象实例都在堆上分配,也是垃圾收集器管理的主要区域,也叫GC堆

      方法区

        存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,别名Non-Heap,非堆,JDK8时已经彻底没有了永久代,将方法区直接放在一个与堆不相连的本地的直接内存区域,这个区域被叫做元空间,

       Hotspot虚拟机直接就把本地方法栈和虚拟机栈合二为一

        运行时常量池

        相较于Class文件常量池,具有动态性,常量并不一定只有在编译期产生,运行时也可将新产生的常量放入池中,存储字面量、符号引用、直接引用的地址等信息,需要注意的是,

       Hotspot在jdk7中已经把原本放在永久代的字符串常量池移出,放在堆内存里,JDK8时因已经彻底没有了永久代,将方法区(包括运行时常量池)直接放在一个与堆不相连的本地直接内存区域,这个区域被叫做元空间

      字符串常量池

        jdk6及以前,都是放在方法区的,jdk7时将字符串常量池移至堆区,jdk8时虽然方法区已取消,运行时常量池移至元空间中,但字符串常量池依旧留在堆中

      常量池(类文件)

        class文件中的一项信息存放编译期生成的各种字面量和符号引用,这部分内容会在类加载后进入方法区的运行时常量池中

        注意:关于JDK8中,方法区、运行时常量池、字符串常量池的关联关系可参考JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

      java栈

        虚拟机栈用于执行普通的Java方法,本地方法栈用于执行本地方法(Native方法),Hotspot虚拟机直接就把本地方法栈和虚拟机栈合二为一

      栈帧

        每个方法在执行的同时都会创建一个栈帧,每个栈帧里存储着局部变量表、操作数栈 动态链接、方法出口等信息

      局部变量表

        所需空间在编译期完成分配,当进入一个方法时局部变量空间是 完全确定的,方法运行期间不会改变,局部变量表里存放着编译期可知的各种基本类型、 对象引用和returnAddress类型(执行一条字节码指令的地址)

      GC

        垃圾回收,对年轻代的垃圾回收即为minor GC,也叫young GC

      线程分配缓冲区

        存在于堆中,但是线程私有,-xx:+/-UseTLAB 是否使用本地线程缓冲

      直接内存

        NIO引入一种基于通道与缓冲区的IO方式,使用Native函数库直接分配堆外内存, 然后通过一个存储在java堆中的DirectByteBuffer对象的引用进行操作

      元空间

        JDK8及以后,由于类的元数据分配在本地内存中,元空间的最大可分配空间就是系统可用内存空间。因此,我们就不会遇到永久代存在时的内存溢出错误,也不会出现泄漏的数据移到交换区这样的事情。

       最终用户可以为元空间设置一个可用空间最大值,如果不进行设置,JVM 会自动根据类的元数据大小动态增加元空间的容量。这里需要注意的是,如果在docker容器里,那么默认的元空间大小为物理机的内存大小,

       此时如果设置了容器的limit,且元空间内存溢出,则将会由系统kill掉,而在容器里的日志中没有kill的信息。

        在元空间中,类和其元数据的生命周期和其对应的类加载器是相同的。换句话说,只要类加载器存活,其加载的类的元数据也是存活的,因而不会被回收掉。在元空间的回收过程中没有重定位和压缩等操作,

       但是元空间内的元数据会进行扫描来确定 Java 引用。

      内存泄露(Memory Leak)

        程序在申请内存后,对象没有被GC所回收,它始终占用内存,内存泄漏的堆积最终会造成内存溢出。

      内存溢出(Memory Overflow)

        程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。通常都是由于内存泄露导致堆栈内存不断增大,从而引发内存溢出

     三、部分区域配置参数

      

      图片摘自网络

      java堆

        -Xms:堆的最小值

        -Xmx:堆的最大值

          以上两个值设置成一样的可避免自动扩展

        -Xmn:年轻代大小

        -XX:MaxNewSize:年轻代的最大值

         -XX:NewSize:年轻代的最小值

        老年代的空间大小没有直接设置的参数

          -Xms 减去 -XX:MaxNewSize,即为老年代的空间大小

      方法区/元空间

        -XX:MaxPermSize:永久代的最大值,JDK8后无效

        -XX:PermSize:永久代的最小值,JDK8后无效

        -XX:MaxMetaspaceSize:元空间的最大值,JDK8及以后

        ‑XX:MinMetaspaceFreeRatio:元空间空闲比例的最小值

        ‑XX:MaxMetaspaceFreeRatio:元空间空闲比例的最大值

      java栈

        -Xss:设置每个线程的堆栈大小

      直接内存

         -XX:MaxDirectMemorySize:设置本机直接内存的最大值,默认与堆最大值一样

     参考:

    《深入理解java虚拟机》

     JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )

    JVM内存区域划分(JDK6/7/8中的变化)

     Java 永久代去哪儿了

  • 相关阅读:
    coredata相关文章,还不错
    Predicates
    iOS5新开发的API总述
    免费Excel教程及模板 微软自带 无木马
    历史的商业行为
    销售激励管理流程和Sales Force Mgmt流程
    亚马逊,应用网关 AWS API GATEWAY
    EXCEL 常用函数公式
    华尔街之狼 原型
    FW:Docker与CI持续集成/CD
  • 原文地址:https://www.cnblogs.com/doclove/p/7613839.html
Copyright © 2011-2022 走看看