jvm 03-java堆内存模型

  • java中最大的特点在于其具备良好的垃圾收集特性
  • GC是整个java之中最重要的安全保证
  • 整个JVM中的GC的处理机制:对不需要的对象进行标记,而后进行清除

JVM堆内存划分

  • 在JDK1.8之后,将最初的永久带内存空间取消了,该图为JDK1.8之前的内存空间组成
  • 取消永久代目的是为了将HotSpot于JRockit两个虚拟机标准联合为一个
  • 在整个JVM堆内存之中实际上将内存分为了三部分:
    • 新生带(年轻代):新对象和没达到一定年龄的对象都在年轻代
    • 老年代:被长时间使用的对象,老年代的内存空间应该要比年轻代更大
    • 元空间(JDK1.8之前叫永久代):像一些方法中的操作临时对象等,JDK1.8之前是占用JVM内存,JDK1.8之后直接使用物理内存

GC流程

  • 基本所有数据都会保存在JVM的堆内存之中
  • 对于整个的GC流程里面,最需要处理的事年轻代与老年代的内存清理操作
  • 元空间(永久代)都不在GC范围内

具体流程:

  1. 当现在有一个新的对象产生,JVM需要为该对象进行内存空间的申请
  2. 先判断Eden区是否有内存空间,如果有,直接将新对象保存在Eden区
  3. 如果Eden区的内存空间不足,会自动执行一个Minor GC操作,将Eden区的无用内存空间进行清理
  4. 清理Eden区之后继续判断Eden区内存空间情况,如果充足,则将新对象直接保存在Eden区
  5. 如果执行了Minor GC之后发现Eden区的内存依然不足,那就判断存活区的内存空间,并将Eden区的部分活跃对象保存在存活区
  6. 活跃对象迁移到存活区后,继续判断Eden区内存空间情况,如果充足,则将新对象直接保存在Eden区
  7. 如果存活区也没有空间了,则继续判断老年区,如果老年区充足,则将存活区的部分活跃对象保存在老年区
  8. 存活区的活跃对象迁移到老年区后,则将Eden区的部分活跃对象保存在存活区
  9. 活跃对象迁移到存活区后,继续判断Eden区内存空间情况,如果充足,则将新对象直接保存在Eden区
  10. 如果老年区也满了,这时候产生Major GC(Full GC)进行老年区的内存清理
  11. 如果老年区执行了Major GC之后发现无法进行对象保存,会产生OutOfMemoryError异常

堆内存参数调整(调优关键)

  • 实际上每一块子内存区中都会存在有一部分的可变伸缩区
  • 如果空间不足时,则在可变范围之内扩大内存空间
  • 当一段时间后,内存空间有余,再将可变空间进行释放

堆内存空间调整参数

  • -Xms:设置初始分配大小,默认为物理内存的1/64
  • -Xmx:最大分配内存,默认为物理内存的1/4
  • -XX:+PrintGCDetails:输出详细的GC处理日志
  • -XX:+PrintGCTimeStamps:输出GC的时间戳信息
  • -XX:+PrintGCDateStamps:输出GC的时间戳信息(以日期的形式)
  • -XX:+PrintHeapAtGC:在GC进行处理的前后打印堆内存信息
  • -Xloggc:(SavePath):设置日志信息保存文件
  • 在堆内存的调整策略中,基本上只要调整两个参数:-Xms和-Xmx

可通过Runtime类获取内存的整体信息

代码如下:

package cn.liang.jvm;
public class memoryTest {
  public static void main(String[] args) {
      Runtime runtime = Runtime.getRuntime();
      long maxMemory = runtime.maxMemory();
      long totalMemory = runtime.totalMemory();
      System.out.println("max_memory=" + maxMemory /(double)1024/1024 + "M");
      System.out.println("total_memory=" + totalMemory /(double)1024/1024 + "M");
  }
}

输出结果:

max_memory=3641.0M
total_memory=245.5M

说明整个内存空间的可变范围(伸缩区):245.5M ~ 3641.0M之间,有可能造成整个程序的性能


为了避免伸缩区的可调策略,使初始化内存等于最大内存,从而提升整个程序性能

输出结果:

max_memory=981.5M
total_memory=981.5M
Heap
 PSYoungGen      total 305664K, used 15729K [0x00000007aab00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 262144K, 6% used [0x00000007aab00000,0x00000007aba5c420,0x00000007bab00000)
  from space 43520K, 0% used [0x00000007bd580000,0x00000007bd580000,0x00000007c0000000)
  to   space 43520K, 0% used [0x00000007bab00000,0x00000007bab00000,0x00000007bd580000)
 ParOldGen       total 699392K, used 0K [0x0000000780000000, 0x00000007aab00000, 0x00000007aab00000)
  object space 699392K, 0% used [0x0000000780000000,0x0000000780000000,0x00000007aab00000)
 Metaspace       used 2708K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 293K, capacity 386K, committed 512K, reserved 1048576K

观察GC的触发操作

代码如下:

package cn.liang.jvm;
import java.util.Random;
public class gctest {
  public static void main(String[] args) {
      Random random = new Random();
      String str = "hello liang";
      while (true) {
          str +=str + random.nextInt(99999999);
          str.intern();
      }
  }
}

输出结果:

[GC (Allocation Failure) [PSYoungGen: 1769K->511K(2560K)] 1769K->775K(9728K), 0.0015982 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2374K->240K(2560K)] 2638K->1119K(9728K), 0.0011725 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2100K->256K(2560K)] 7841K->5996K(9728K), 0.0005402 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 256K->240K(2560K)] 5996K->5980K(9728K), 0.0005811 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 240K->0K(2560K)] [ParOldGen: 5740K->3925K(7168K)] 5980K->3925K(9728K), [Metaspace: 2662K->2662K(1056768K)], 0.0064126 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 41K->32K(2560K)] 6397K->6388K(9728K), 0.0003653 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 32K->32K(1536K)] 6388K->6388K(8704K), 0.0003294 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 32K->0K(1536K)] [ParOldGen: 6356K->2710K(7168K)] 6388K->2710K(8704K), [Metaspace: 2662K->2662K(1056768K)], 0.0035285 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 19K->0K(2048K)] 5160K->5140K(9216K), 0.0004489 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] 5140K->5140K(9216K), 0.0003114 secs] [Times: user=0.00 sys=0.01, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] [ParOldGen: 5140K->5140K(7168K)] 5140K->5140K(9216K), [Metaspace: 2662K->2662K(1056768K)], 0.0030502 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] 5140K->5140K(9216K), 0.0003198 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2048K)] [ParOldGen: 5140K->5127K(7168K)] 5140K->5127K(9216K), [Metaspace: 2662K->2662K(1056768K)], 0.0039555 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  at java.util.Arrays.copyOf(Arrays.java:3332)
  at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
  at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
  at java.lang.StringBuilder.append(StringBuilder.java:136)
  at cn.liang.jvm.gctest.main(gctest.java:11)
Heap
 PSYoungGen      total 2048K, used 40K [0x00000007bfd00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1024K, 3% used [0x00000007bfd00000,0x00000007bfd0a120,0x00000007bfe00000)
  from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
  to   space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
 ParOldGen       total 7168K, used 5127K [0x00000007bf600000, 0x00000007bfd00000, 0x00000007bfd00000)
  object space 7168K, 71% used [0x00000007bf600000,0x00000007bfb01c78,0x00000007bfd00000)
 Metaspace       used 2693K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 292K, capacity 386K, committed 512K, reserved 1048576K

日后如果发现你的程序执行速度变慢了,可以针对程序的运行内存进行分析

  • 可视化工具:..\Java\jdk1.8.0_131\bin\jvisualvm.exe
  • 命令查看:jmap(jmap -heap JavaPID)

原文地址:https://www.cnblogs.com/liangjingfu/p/9929229.html

时间: 2024-09-29 16:11:56

jvm 03-java堆内存模型的相关文章

Java 堆内存模型

堆内存 Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象. 在 Java 中.堆被划分成两个不同的区域:新生代 ( Young ).老年代 ( Old ).新生代 ( Young ) 又被划分为三个区域:Eden.From Survivor.To Survivor. 这样划分的目的是为了使 JVM 可以更好的管理堆内存中的对象.包含内存的分配以及回收. 堆的内存模型大致为: 从图中能够看出: 堆大小 = 新生代 + 老年代.当中,堆的大小能够通过參数 –Xms

Java堆内存模型

在了解这一块知识的时候,需要知道jdk1.8之前与jdk1.8及之其之后的区别 新生代: 刚创建的对象, 有可能经历过几次GC 老年代: 经历过多次GC之后,仍然存活的对象 永久代: 比如intern()方法入池的对象实际上就进入了永久代, 永久代不会被回收.因为其本身属于一个bug性的存在,所以在jdk1.8之后,将其更换元空间(电脑的直接内存). 至于具体细节,略吧! 原文地址:https://www.cnblogs.com/z-qinfeng/p/12208832.html

JVM运行时数据区与JVM堆内存模型小结

前提 JVM运行时数据区和JVM内存模型是两回事,JVM内存模型指的是JVM堆内存模型. 那JVM运行时数据区又是什么? 它包括:程序计数器.虚拟机栈.本地方法栈.方法区.堆. 来看看它们都是干嘛的 程序计数器:保存当前线程执行的指令的地址(大意如此). 虚拟机栈:由栈帧组成,而每个栈帧又包括局部变量表.操作数栈.动态连接(调用其他方法).出口(被调用时返回值) -- 每个栈帧就代表了一个方法的执行. 本地方法栈:类似虚拟机栈,只不过方法改成了native方法. 方法区:保存了类的各种信息.类的

深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)视频教程

14套java精品高级架构课,缓存架构,深入Jvm虚拟机,全文检索Elasticsearch,Dubbo分布式Restful 服务,并发原理编程,SpringBoot,SpringCloud,RocketMQ中间件,Mysql分布式集群,服务架构,运 维架构视频教程 14套精品课程介绍: 1.14套精 品是最新整理的课程,都是当下最火的技术,最火的课程,也是全网课程的精品: 2.14套资 源包含:全套完整高清视频.完整源码.配套文档: 3.知识也 是需要投资的,有投入才会有产出(保证投入产出比是

Java虚拟机内存模型及垃圾回收监控调优

Java虚拟机内存模型及垃圾回收监控调优 如果你想理解Java垃圾回收如果工作,那么理解JVM的内存模型就显的非常重要.今天我们就来看看JVM内存的各不同部分及如果监控和实现垃圾回收调优. JVM内存模型         正如你上图所看到的,JVM内存可以划分为不同的部分,广义上,JVM堆内存可以划分为两部分:年轻代和老年代(Young Generation and Old Generation) 年轻代(Young Generation) 年轻代用于存放由new所生成的对象.当年轻代空间满时,

Java堆内存

??Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象. ??在 Java 中,堆被划分成两个不同的区域:新生代 ( Young ).老年代 ( Old ).新生代 ( Young ) 又被划分为三个区域:Eden.From Survivor.To Survivor. ??这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收. ??堆的内存模型大致为: ??新生代:Young Generation,主要用来存放新生的对象. ??老

浅析Java的内存模型

一.前言 ??之前过年在家,空闲时间比较多,想要了解一下JVM相关的内容,于是买了<深入理解Java虚拟机>这本书,过了一遍其中的基础知识.时隔多日,都忘得差不多了.为了重新捡起来,我决定复习一遍,并编写相关的系类博文加深印象,这是第一篇,来讲一讲JVM最基础的内容--Java的内存模型. 二.正文 ?2.1 Java内存分布 ??Java的内存主要分为五个部分: 程序计数器: Java虚拟机栈: 本地方法栈: 堆内存: 方法区: ??具体结构如下图所示: 2.2 程序计数器 ??首先看第一部

java线程内存模型,线程、工作内存、主内存

转自:http://rainyear.iteye.com/blog/1734311 java线程内存模型 线程.工作内存.主内存三者之间的交互关系图: key edeas 所有线程共享主内存 每个线程有自己的工作内存 refreshing local memory to/from main memory must  comply to JMM rules 产生线程安全的原因 线程的working memory是cpu的寄存器和高速缓存的抽象描述:现在的计算机,cpu在计算的时候,并不总是从内存读

Java堆内存不足

1)使用IDEA开发程序时有时候会提示“Java Heap space error”,说明IDEA默认配置的Java堆内存不足,程序需要更多的堆内存. 2)堆(Heap)和非堆(Non-heap)内存     按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时创建的.”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”.可以看出JVM主要管理两种类型的内存:堆和非堆.简单来说堆就是Java代码

关于java堆内存溢出的几种情况(转)

[情况一]: java.lang.OutOfMemoryError: Java heap space:这种是java堆内存不够,一个原因是真不够,另一个原因是程序中有死循环: 如果是java堆内存不够的话,可以通过调整JVM下面的配置来解决: <jvm-arg>-Xms3062m</jvm-arg> <jvm-arg>-Xmx3062m</jvm-arg> [情况二] java.lang.OutOfMemoryError: GC overhead limit