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 永久代去哪儿了

  • 相关阅读:
    Reactive Extensions (Rx) 入门(5) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(4) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(3) —— Rx的事件编程
    Reactive Extensions (Rx) 入门(2) —— 安装 Reactive Extensions
    Reactive Extensions (Rx) 入门(1) —— Reactive Extensions 概要
    Xamarin NuGet 缓存包导致 already added : Landroid/support/annotation/AnimRes 问题解决方案
    Android 系统Action大全
    Xamarin Forms 实现发送通知点击跳转
    如何理解灰度发布
    推荐一款分布式微服务框架 Surging
  • 原文地址:https://www.cnblogs.com/doclove/p/7613839.html
Copyright © 2011-2022 走看看