美文网首页
简谈JVM之堆分析

简谈JVM之堆分析

作者: M问道 | 来源:发表于2018-04-01 09:47 被阅读0次

    JVM的内存模型

    线程私有区域

    1. Program Counter Register(程序计数器)
      一块较小的内存空间, 作用是当前线程所执行字节码的行号指示器.
      不同于OS以进程为单位调度, JVM中的并发是通过线程切换并分配时间片执行来实现的. 在任何一个时刻, 一个处理器内核只会执行一条线程中的指令. 因此, 为了线程切换后能恢复到正确的执行位置, 每条线程都需要有一个独立的程序计数器, 这类内存被称为“线程私有”内存。

    2. Java Stack(虚拟机栈)
      虚拟机栈描述的是Java方法执行的内存模型: 每个方法被执行时会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息. 每个方法被调用至返回的过程, 就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程(VM提供了-Xss来指定线程的最大栈空间, 该参数也直接决定了函数调用的最大深度)。

    3. Native Method Stack(本地方法栈)
      与Java Stack作用类似, 区别是Java Stack为执行Java方法服务, 而本地方法栈则为Native方法服务。

    线程共享区域

    1. Heap(Java堆)
      几乎所有对象实例和数组都要在堆上分配(栈上分配、标量替换除外), 因此是VM管理的最大一块内存, 也是垃圾收集器的主要活动区域. 由于现代VM采用分代收集算法, 因此Java堆从GC的角度还可以细分为: 新生代(Eden区、From Survivor区和To Survivor区)和老年代。

    2. Method Area(方法区)
      即我们常说的永久代(Permanent Generation), 用于存储被JVM加载的类信息、常量、静态变量。 HotSpot VM把GC分代收集扩展至方法区, 即使用Java堆的永久代来实现方法区(永久带的内存回收的主要目标是针对常量池的回收和类型的卸载, 因此收益一般很小)。

    直接内存
    直接内存并不是JVM运行时数据区的一部分, 但也会被频繁的使用: 在JDK 1.4引入的NIO提供了基于Channel与Buffer的IO方式, 它可以使用Native函数库直接分配堆外内存, 然后使用DirectByteBuffer对象作为这块内存的引用进行操作(详见: Java I/O 扩展), 这样就避免了在Java堆和Native堆中来回复制数据, 因此在一些场景中可以显著提高性能.
    显然, 本机直接内存的分配不会受到Java堆大小的限制(即不会遵守-Xms、-Xmx等设置), 但既然是内存, 则肯定还是会受到本机总内存大小及处理器寻址空间的限制, 因此动态扩展时也会出现OutOfMemoryError异常。

    OOM场景

    1. 堆内存溢出
      堆内存分配超过最大内存xmx
      解决方案:适当增大堆内存,及时释放内存
    2. 永久区溢出
      创建了大量的类,导致超过永久区最大内存限制permMaxSize
      解决方案:适当增大perm区大小,允许class回收(+Xnoclassgc)
    3. 栈溢出
      创建大量的线程或者线程分配大量的栈内存
      解决方案:减少堆内存,减小线程栈空间大小(xss)
    4. 直接内存溢出
      ByteBuffer.allocateDirect()无法从操作系统获得足够的空间(操作系统可分配内存包含三块:堆内存、栈内存、直接内存)
      解决方案:减小堆内存,显示触发GC

    对象的内存布局

    1. 对象头
      存储对象自身的运行时数据(锁状态标志、线程持有的锁、偏向线程id)---mark wor;类型指针(对象指向类元数据指针,jvm确定这个对象是哪个类实例)
      对象头在32位操作系统8B,64位操作系统是16B。
    2. 实例数据
    3. 对齐填充

    对象采用8字节对齐,优势在于尽可能减少cpu读取内存次数。一个时钟周期32位操作系统可以连续读取4个字节内存,64位操作系统可以连续读取8个字节内存。如果在64位操作系统,不对齐的情况下内存正好在奇数位cpu需要多一次读取。

    堆分析

    堆分析的工具很多,比如说Mat、VisualVm、TProfiler等。堆分析 其中会涉及到浅堆和深堆的概念,浅堆值一个对象数据结构所占用的大小,深堆指一个对象被GC后可以真实释放的大小,即只能通过对象访问的(直接或者间接)所有对象的浅堆之和。
    工具既提供了图形化工具,标识对象占用内存大小和个数,还可以查看引用该对象的内存和该内存引用对象内存情况。工具还提供了查询工具,使用OQL语句,语法类似SQL语句。

    selecte s.creationTime from org.apache.catalina.session.StandardSession s
    

    相关文章

      网友评论

          本文标题:简谈JVM之堆分析

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