【JVM】堆体系结构及其内存调优
堆体系结构
一个JVM实例只存在一个堆内存,堆内存的大小是可调节的。类加载器读取类文件后,需要把类、方法、常量、变量放在堆内存中,保存所有引用类型的真实信息,以方便执行器指向,堆内存分为三个部分:年轻代、老年代、永久代。
Java7之前,堆内存在逻辑上分为:年轻代、老年代、永久代。物理上分为:年轻代、老年代
Java8:永久代 ---> 元空间
新生区是类的诞生、成长、消亡的区域。一个类在新生区产生,最后被垃圾回收器收集。新生区分为伊甸区和幸存者区。幸存者区分为幸存0区,幸存1区。
当伊甸区空间用完的时候,程序还需要创建对象,JVM的垃圾回收器将对伊甸区进行垃圾回收(Minor GC),将伊甸区中不再被其他对象引用的对象进行销毁,将剩余的对象移动到幸存0区。
若幸存0区(from区)满了,对幸存0区进行垃圾回收,将剩余的对象移动到幸存1区。如果幸存1区(to区)满了,再移动到养老区。
如果养老区满了,就产生了Major GC(Full GC),进行养老区的内存清理。如果执行了Full GC后依然无法进行对象的保存,就会产生OOM异常,OutOfMemoryError。
异常:java.lang.OutOfMemoryError: Java heap space
JVM堆内存不够,原因:
- JVM的堆内存设置的太小,可以调整-Xms、-Xmx
- 代码中创建了大量的大对象,并且长时间不能被垃圾回收器收集(存在被引用)
Minor GC的过程
Java堆从GC的角度可以细分为新生代(Eden区、from 存活区、to 存活区,空间比例8:1:1)和老年代(空间比例1:2)。
复制 ☞ 清空 ☞ 互换
1. eden、survivor from 复制到 survivor to,对象年龄+1。
当eden区满,触发第一次GC,存活对象拷贝到survivor from区。当eden区再次触发GC,会扫描eden和from,对这两个区进行垃圾回收,将存活的对象,复制到to区,对象年龄+1。(如果有对象年龄达到了老年的标准,拷贝到老年代,对象年龄+1)
2. 清空eden、survivor from
清空eden和survivor from中对象,此时from为。
3. survivor from 和 survivor to 互换
to区存在对象,变成下一次GC的from区,from区成为下一次GC的to区,部分对象会在form和to区域复制往来15次(JVM的MaxTenuringshold参数默认是15),如果最终还是存活,就存入老年代。
方法区和永久代
参考自博客:https://www.jianshu.com/p/66e4e64ff278
在JDK1.6及之前,运行时常量池是方法区的一个部分,同时方法区里面存储了类的元数据信息、静态变量、即时编译器编译后的代码(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等)等。在JDK1.7及以后,JVM已经将运行时常量池从方法区中移了出来,在JVM堆开辟了一块区域存放常量池。
方法区和堆都是各个线程共享的内存区域,方法区用于存储虚拟机加载的类信息、普通常量、静态常量、编译器编译后的代码等,虽然JVM规范将方法区描述为堆的一个逻辑部分,但它还有一个别名叫Non-Heap,目的是和堆分开。
方法区常被成为永久代,严格来说二者不同,只是用永久代来实现方法区而已,方法区和永久代的关系很像Java中接口和类的关系,类实现了接口,而永久代就是HotSpot虚拟机对虚拟机规范中方法区的一种实现方式。
永久代在JDK1.7之前有,是一个常驻内存区域,用于存放JDK自身携带的class、interface的元数据,也就是说它存储的是运行环境必须的类信息,被装在进此区域的数据是不会被垃圾回收器回收掉的,关闭jvm才会释放这个区域所占的内存。
HotSpot虚拟机中存在三种垃圾回收现象,minor GC、major GC和full GC。对新生代进行垃圾回收叫做minor GC,对老年代进行垃圾回收叫做major GC,同时对新生代、老年代和永久代进行垃圾回收叫做full GC。许多major GC是由minor GC触发的,所以很难将这两种垃圾回收区分开。major GC和full GC通常是等价的,收集整个GC堆。但因为HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了,当有人说“major GC”的时候一定要问清楚他想要指的是上面的full GC还是major GC。
元空间
参考自博客:https://www.jianshu.com/p/66e4e64ff278
堆内存调优
在JDK1.7中
在JDK1.8中,元空间取代永久代。元空间和永久代的最大的区别是永久代使用的是JVM的堆内存,元空间不在虚拟机中,而是使用本机物理内存。默认清空下,元空间只受本地内存限制,类的元数据放入本地内存,字符串常量池和类型静态变量放入java堆,类的元数据的加载量不再受MaxPermSize控制,而是由系统实际的可用空间来控制。
-Xms:初始分配大小,默认为物理内存的1/64
-Xmx:最大分配内存,默认为物理内存的1/4
-XX:+PrintGCDetails:输出详细的GC处理日志
配置完Xms、Xmx后的输出结果
java.lang.OutOfMemoryError: Java heap space异常GC处理日志:
[GC (Allocation Failure) [PSYoungGen: 2045K->488K(2560K)] 2045K->781K(9728K), 0.0014360 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2534K->488K(2560K)] 2827K->1548K(9728K), 0.0008101 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2171K->504K(2560K)] 4318K->3194K(9728K), 0.0006870 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 2207K->0K(2560K)] [ParOldGen: 7037K->2826K(7168K)] 9245K->2826K(9728K), [Metaspace: 3454K->3454K(1056768K)], 0.0051352 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 5000K->5000K(9728K), 0.0003304 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 5000K->5000K(9728K), 0.0002962 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 5000K->3913K(7168K)] 5000K->3913K(9728K), [Metaspace: 3455K->3455K(1056768K)], 0.0028924 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 3913K->3913K(8704K), 0.0005099 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 3913K->3889K(7168K)] 3913K->3889K(8704K), [Metaspace: 3455K->3455K(1056768K)], 0.0072665 secs] [Times: user=0.06 sys=0.02, real=0.01 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:674)
at java.lang.StringBuilder.append(StringBuilder.java:208)
at day05JVM01.T2.main(T2.java:15)
YoungGC
[GC (Allocation Failure) 内存分配失败
[PSYoungGen: 2045K->488K(2560K)] 2045K->781K(9728K), 0.0014360 secs]
[GC类型:GC前young区的内存占用->GC后young区的内存占用(新生代的总内存)] GC前JVM堆内存占用->GC后JVM堆内存占用(JVM堆的总内存),GC耗时
[Times: user=0.00 sys=0.00, real=0.00 secs]
[GC用户耗时,系统耗时,实际耗时]
FullGC
[Full GC (Allocation Failure)
[PSYoungGen: 0K->0K(1536K)]
[ParOldGen: 3913K->3889K(7168K)] 3913K->3889K(8704K),
[Metaspace: 3455K->3455K(1056768K)], 0.0072665 secs]
[Times: user=0.06 sys=0.02, real=0.01 secs]
什么是GC?
GC是分类收集算法,JVM在进行GC的时候并不是每次对三个区域一起回收,大部分时候是回收新生代。频繁收集Young区,较少收集Old区,基本不动元空间。GC按照回收的区域分成了:普通GC minor GC和全局GC Full GC
Minor GC:只针对新生代区域的GC,发生在新生代的垃圾收集,因为大多数JAVA对象存活率都不高,所以Minor GC的操作非常频繁,垃圾回收的速度比较快。
Full GC:指发生在老年代的垃圾收集操作,出现Full GC,经常会伴随至少一次的Minor GC(但不绝对)。Full GC的速度一般比Minor GC 慢10倍以上。
GC有四大算法:引用计数法、复制算法、标记清除、标记压缩。
【JVM】堆体系结构及其内存调优的更多相关文章
- JVM参数配置及内存调优
一.JVM常见参数配置 堆内存相关参数 参数名称 含义 默认值 -Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40% ...
- 阿里P8Java大牛仅用46张图让你弄懂JVM的体系结构与GC调优。
本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.图文并茂不生枯燥. 此PPT长达46页,全部展示篇幅过长,本文优先分享前十六页 ...
- JVM探究 面试题 JVM的位置 三种JVM:HotSpot 新生区 Young/ New 养老区 Old 永久区 Perm 堆内存调优GC的算法有哪些?标记清除法,标记压缩,复制算法,引用计数法
JVM探究 面试题: 请你弹弹你对JVM的理解?Java8虚拟机和之前的变化更新? 什么是OOM?什么是栈溢出StackOverFlowError?怎么分析 JVM的常用调优参数有哪些? 内存快照如何 ...
- JVM、垃圾回收、内存调优、常见參数
一.什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写.JVM是一种用于计算设备的规范.它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现 ...
- JVM实用参数(四)内存调优
理想的情况下,一个Java程序使用JVM的默认设置也可以运行得很好,所以一般来说,没有必要设置任何JVM参数.然而,由于一些性能问题(很不幸的是,这些问题经常出现),一些相关的JVM参数知识会是我们工 ...
- JVM学习笔记(四)------内存调优【转】
转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内 ...
- JVM学习笔记(四)------内存调优
首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提 ...
- 【Spark篇】---Spark调优之代码调优,数据本地化调优,内存调优,SparkShuffle调优,Executor的堆外内存调优
一.前述 Spark中调优大致分为以下几种 ,代码调优,数据本地化,内存调优,SparkShuffle调优,调节Executor的堆外内存. 二.具体 1.代码调优 1.避免创建重复的RDD,尽 ...
- 我进行jvm内存调优的一些记录
jvm内存调优的一些记录 java内存调优的方法和过程 可以使用 jmap -heap pid号 查看,例如pid是9300,执行的结果可能是这样的. root@ubuntu:~# jmap -hea ...
随机推荐
- System.Linq.Dynamic字符串转委托
以前一直想着有没有一个方法能够把字符串直接转化成函数的,刚好有需求就找了下,还真有. 微软地址:https://docs.microsoft.com/en-us/previous-versions/b ...
- B. Heaters 思维题 贪心 区间覆盖
B. Heaters 这个题目虽然只有1500的分数,但是我还是感觉挺思维的,我今天没有写出来,然后看了一下题解 很少做这种区间覆盖的题目,也不是很擅长,接下来讲讲我看完题解后的思路. 题目大意是:给 ...
- spring mvc 实现文件上传
例:用户注册提交一个头像文件 第一步,创建项目 ,导入jar包 做文件上传除了要导入spring常规的jar包外,还要导入commons-fifileupload和commons-io这两个jar包. ...
- mybatis传递参数的方法
一.传递一个参数 例:根据员工编号查询员工的基本信息 1.在dao接口中声明一个方法 2.在mapper中实现该方法 3.测试 /** * 传递一个参数 */ public class Test02 ...
- Spring官网阅读(二)(依赖注入及方法注入)
上篇文章我们学习了官网中的1.2,1.3两小节,主要是涉及了容器,以及Spring实例化对象的一些知识.这篇文章我们继续学习Spring官网,主要是针对1.4小节,主要涉及到Spring的依赖注入.虽 ...
- 测试开发专题:spring-boot自定义异常返回
上文测试开发专题:spring-boot统一异常捕获我们讨论了java异常以及如何使用Spring-Boot捕获异常,但是没有去说捕获异常后该如何进一步处理,这篇文章我们将对这个遗留的问题进行讨论. ...
- Linux Charger IC 驱动移植总结
Linux Charger IC 驱动移植总结 文章目录 Linux Charger IC 驱动移植总结 1 设备树的基本知识 设备树的概念 设备树的基本结构 compatible属性 举个栗子 2 ...
- 74LS 系列 名称解释
摘自:http://blog.sina.com.cn/s/blog_502ffce50100j9db.html -------------------------------------------- ...
- 爬取淘宝商品信息,放到html页面展示
爬取淘宝商品信息 import pymysql import requests import re def getHTMLText(url): kv = {'cookie':'thw=cn; hng= ...
- 到手的DEM不会用?教你6个常用强大功能
一.概述 DEM是数字高程模型(Digital Elevation Model)的简称,接触GIS,规划,设计类的多多少少会接触到DEM,可是这个直接查看黑溜溜一片DEM到底可以用来做什么呢? 二.背 ...