美文网首页
JVM(一)java内存区域

JVM(一)java内存区域

作者: 7ColorLotus | 来源:发表于2020-05-28 23:35 被阅读0次
    • Sun/Oracle系列的虚拟机

      1. Sun Classic/Exact VM 第一款商用JAVA虚拟机
      2. HotSpot VM 目前使用范围最广的JAVA虚拟机
      3. Mobile系列 面对移动和嵌入式市场
    • 其他公司的虚拟机

      1. BEA JRockit
      2. IBM J9 VM
      3. BEA Liquid VM
      4. Google Android Dalvik VM
      5. Apache Harmony
      6. Microsoft JVM及其他
    • 未来的的JAVA技术

      1. 模块化
      2. 混合语言
      3. 多核并行
      4. 丰富语法
      5. 64位
      6. 更强的垃圾回收
    • 运行时数据区域

      1. 定义:java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域

      2. 类型:
        1> 程序计数器:较小的内存空间,当前线程执行的字节码的行号指示器;各个线程之间独立存储,互不影响
        2> 虚拟机栈:线程私有,生命周期和线程,每个方法在执行的同事都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息。方法的执行就对应着栈帧在虚拟机栈中入栈和出栈的过程;栈里面存放着各种基本数据类型和对象的应用(-XSS),默认大小1M
        3> 本地方法栈:本地方法栈保存的是navtive方法的信息,当一个JVM创建的线程调用native方法后,JVM不再为其在虚拟机栈中创建栈帧,JVM只是简单地动态链接并直接调用native方法
        4> java堆:java堆是javaver需要重点关注的一块区域,因为涉及到内存的分配(new关键字,反射等)与回收(回收算法,收集器等)

           a, -Xms 堆的最小值
           b, -Xmx 堆的最大值
           c, -Xmn 新生代的大小
           d, -XX:NewSize 新生代最小值
           e, -XX:MaxNewSize 新生代最大值
        

        5> 方法区(jdk7以后不存在了):也叫永久区,用于存储已经被虚拟机加载的类信息,常量("zsd","123"等),静态变量(static变量)等数据

           a, -XX:PermSize(jdk7及以前)
           b, -XX:MaxPermSize(jdk7及以前)
           c, -XX:MetaspaceSize(jdk7以后)
           d, -XX:MaxMetaspaceSize(jdk7以后)
        

        6> 运行时常量池:运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量("zsd","123"等)和符号引用。jdk7后放在堆里,jdk7即以前放在方法区里

           a, 永久代来存储类信息、常量、静态变量等数据不是个好主意,很容易遇到内存溢出的问题。
           b, 对永久代进行调优是很难的,同时将元数据空间(本地内存)与堆的垃圾回收进行了隔离,避免永久代引发的Full GC和OOM等问题
        

        7> 直接内存:不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域;网络推送使用最多

           a, 如果使用NIO,这块区域会被频繁使用,在java堆内可以用directByteBuffer对象直接引用并操作
           b, 这块内存不受java堆大小限制,但受本机总内存的限制,可以通过MaxDirectMemorySize来设置(默认与堆内存最大值一样),所以也会出现OOM异常
        
      3. JDK1.6内存区域


        JDK1.6内存区域.png
      4. JDK1.7内存区域


        JDK1.7内存区域.png
    • 站在线程角度来看java内存区域

      1. 线程共享内存区:java堆,方法区
      2. 线程私有内存区:虚拟机栈,本地方法栈,程序计数器。随着线程产生和消亡,因此不需要过多考虑内存回收的问题。编译时确定所需内存大小
    • 深入辨析堆和栈

      1. 功能
        1> 以栈帧的方式存储方法调用的过程,并存储方法调用过程中基本数据类型的变量(Int,short,long,byte,float,double,boolean,char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放;
        2> 而堆内存用来存储Java中的对象。无论是成员变量,还是类变量,他们指向的对象都存储在堆内存中

      2. 线程独享还是共享
        1> 栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存
        2> 堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问

      3. 空间大小
        1> 栈的内存要远远小于堆内存,栈的深度是有限制的,可能发生StackOverFlowError问题

    • 方法的出入栈

      1. 方法会打包成栈帧,一个栈帧至少要包含局部变量表,操作数栈和帧数据区
      2. 栈上分配
        1> 跟着函数调用自行销毁,提高性能
        2> 逃逸分析 : 判断方法内的变量是否会逃出函数体
        3>栈上分配演示
        a, -server: JVM运行的模式,才能进行逃逸分析 。其他选项:mix/client
        b, -Xmx 10m: 堆的大小
        c, -XX:+DoEscapeAnalysisi:启用逃逸分析。"+"开启功能,"-"关闭功能
        d, -XX:+PrintGC:打印GC日志
        e, -XX:+EliminateAllocations:标量替换。变成"-"就不是栈上分配
        f, -XX:-UseTLAB:TLAB(ThreadLocalAllocBuffer)事先为每个线程分配一块私有内存
    • 虚拟机中的对象的初始化过程

      1. 检查加载
      2. 分配内存
        1> 划分内存:指针碰撞和空闲列表
        2> 并发安全问题:用CAS配上失败重试本地线程分配缓冲
      3. 内存空间初始化
      4. 设置
      5. 对象初始化
    • 对象的内存布局

      1. 对象头:对象自身的运行数据(hashCode等)和类型指针
      2. 实例数据:程序代码中所定义的各种类型的字段内容
      3. 对齐填充:虚拟机处理,占位,对象的大小必须是8个字节整数倍
    • 对象的访问定位

      1. 使用句柄:指向句柄(类似指示牌)池

      2. 直接指针:hotspot虚拟机使用的访问方式

      3. 示例图

        对象访问定位.png
    • 堆参数设置,对性能的影响和内存溢出实战

      1. java堆溢出
        1> java.lang.OutOfMemoryError: Java heap space 在分配的时候,有巨型对象在分配
        2> java.lang.OutOfMemoryError: GC overhead limit exceeded 某个循环里不停的分配对象,但是分配太多,把堆撑爆了
      2. 新生代配置
        1> -XX:NewSize/MaxNewSize 优先级最高
        2> -Xmn (NewSize=MaxNewSize) 优先级第二
        3> -XX:NewRatio 新生代和老年代的比例 优先级最小
        4> -XX:SurvivorRatio 表示eden和Surviror的比值,缺省为8 Eden:FromS:ToS = 8:1:1
        5> 示例 生成10M
        -Xms20M -Xmx20M -XX:+PrintGCDetails -Xmn2m -XX:SurvivorRatio=2
        -Xms20M -Xmx20M -XX:+PrintGCDetails -Xmn7m -XX:SurvivorRatio=2
        -Xms20M -Xmx20M -XX:+PrintGCDetails -Xmn15m -XX:SurvivorRatio=8
        -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:NewRatio=2 新生代和老年代比例 1:2
      3. 方法区和运行时常量池溢出
      4. 虚拟机栈和本地方法栈溢出
        1> java.lang.StackOverFlowError 要考虑是否有无限递归
      5. 本机直接内存溢出
        1> ByteBuffer b = ByteBuffer.allocateDirect(size)

    相关文章

      网友评论

          本文标题:JVM(一)java内存区域

          本文链接:https://www.haomeiwen.com/subject/fbktzhtx.html