通过之前的学习我们知道程序计数器、虚拟机栈、本地方法栈这3个区域随着线程而生,随线程而灭。栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的。因此这几个区域的内存分配和回收都具备确定性,无需过多考虑内存回收的问题。而Java堆则是我们关注的重点。

Java中最大的特点在于具备良好的垃圾收集器。GC是JAVA中最重要的安全保证。

整个JVM中的GC的处理机制:对不需要的对象进行标记,而后进行清除。

一. 堆内存划分

note:(1.8之前元空间的位置是永久代,这是最大的变化)。JDK1.8开始,之前的永久代空间取消了。取消永久代的目的是为了将HotSpot与JRocket两个虚拟机标准合成一个,因为以前只有HotSpot才有永久代。

在整个的JVM堆内存之中实际上将内存分为了三块:

  • 年轻代:新对象和没达到一定年龄的对象都在年轻代;(比如18岁前)

新生对象在Eden,而年龄达到一定的在SO或者S1,还有伸缩区域可以扩展;

  • 年老代:对象被长时间使用的对象。(比如18岁到80岁),老年代的内存空间应该比年轻代的内存空间更大。
  • 元空间:像一些方法中的操作临时对象等,直接使用物理内存;

最初的永久代是需要在JVM堆内存里面进行划分;而元空间直接使用物理内存;

为何分区:是为了更好的进行每一块的管理(好比磁盘分区管理),可以确定哪一块内存可以被清空,哪一块不能。

二. GC流程

所有的数据都会保存在JVM的堆内存之中,但是在实际的开发中经常会创建许多的临时对象,也会有一些常驻对象在(比如单例),所以为了保证GC的性能问题,对于GC的处理流程如下图所示:

对于GC流程里面,那么最需要处理的就是年轻代与老年代内存清理操作,而元空间(永久代)都不在GC范围内。其实元空间和永久代差不多,只是一个是内部内存,一个是外部内存。

  图的说明如下:

  • 当现在有一个新的对象产生(Eden),那么对象一定需要内存空间,于是现在就需要为该对象进行内存空间的申请。
  • 首先会判断Eden园区是否有内存空间,如果此时有内存空间,则直接将新对象保存在Eden区域;如果此时Eden内存空间不足,那么他会出发一个Minor GC操作,将Eden的无用内存空间进行清理。(分区的好处不会影响到别的区域);清理之后会继续判断Eden的内存空间是否充足。充足的话则将新的对象直接在Eden进行空间分配;如果执行了Minor GC后,Eden内存任然不足,那么这个时候会进行存活区的内存判断,则会将Eden的部分对象存在存活区,(Eden就会空出一部分空间出来了),那么这个时候又继续判断Eden的空间是否够,够就存。  如果存活区也没有内存空间了,那么就继续判断老年区。如果此时老年区的空间充足,则将存活区中的活跃对象保存到老年代,而后存活区就会出现空余空间,随后Eden将活跃对象保存到存活区之中,从而为Eden开辟内存空间。--------------说明所有的新对象都会在Eden区。
  • 如果这个时候老年代也满了,那么这个时候将产生Major GC(Full GC),那么这个时候就会进行老年代的垃圾清理。
  • 如果老年代执行了Full GC之后发现仍然无法进行对象的保存,就会产生OOM异常,OutOfMemoryError.

三. JVM内存调整参数(调优关键)

通过之前的分析发现,实际上每一块子内存区域中都会存在有一部分的可变伸缩区域,其基本流程为:如果空间不足,则在可变的空间范围内,扩展内存空间;当一段时间内,发现内存空间不那么紧张了,因此开始收缩内存空间。(因为判断伸缩是花时间的,因此它是调优的关键,我们应该尽量让这个伸缩区域不存在)。

前两个最常用。

在整个堆内存的调整策略之中,有经验的人基本上都只会调整两个参数(前两个):一个叫做最大内存,一个叫做初始化内存如果让这两个相等,那么就没有可变的范围,性能就可以提升。如果要想取得这些内存的整体信息直接利用Runtime类即可。

上面的单位是字节,最好用M单位来表示,就除以两个1024

根据结果会发现:默认情况下分配的内存是总内存的“1/4”(上面的总内存是32G).而初始化的内存为1/64.那么伸缩区就是491.0M到7276.5M之间,那么现在就有可能造成程序的性能下降。那么最好的做法就是让这两个参数一样大小。那么这个时候就避免了伸缩去的可调策略,从而提升了整个程序的性能。

比如这样:

note:在eclipse里面可以配置的,比如打开Run configuratios----VM arguments

四. 年轻代

所有的新对象都会在年轻代产生。如果年轻代的空间的不足,无法生成对象,则会引发Minor GC和Major GC(Full GC)。

所有使用关键字new新实例化的对象一定会在Eden保存,而存活区保存的一定是已经在Eden中存在好久并且经过了好几次的Minor GC还保存下来的存活对象。那么这个对象将晋升到存活区之中。存活区分为两个存活区,而且这两个存活区一定是相等的大小。目的:一块存活区为了晋升,另外一块为了对象回收。Fromto不固定,是会互相换的。这两块内存空间一定有一块是空的。

 Minor GC的算法如下图:

在年轻代中使用的是Minor GC,这种GC算法采用的是复制算法。

解释:当Eden空间不足的时候,会把存活对象上升到存活区中,即把绿色放到存活区中的。当存活区中的GC完了以后,将统一把存活对象放到一个存活区中,另外一个存活区就会被清空。

通过以上的分析可以发现,在整个的处理过程中,Eden中大多说都是临时的新对象,可能会发生频繁的Minor GC,所以在HotpSpot虚拟机之中为了加快此空间的内存分配,所以采用了两种技术优化实现:Bump-The-Pointer和Thread-LocalAllocation Buffers.

五. 老年代

老年代主要是接收由年轻代发来的对象。一般是经过了好几次Minor GC后的。如果你要保存的对象超过了Eden大小,那么这个对象可以直接保存到老年代。当老年代内存不足时,将引发Full GC.(Major GC)

老年代中的算法有2个:

在回收清除的过程之中,发现所有在老年代被回收的对象并没有进行空间的整理,所以老年代里面最头太疼的问题就是碎片问题。于是还有第二种算法:

所以:以后在进行老年代存储的时候,尽可能保存长期会被使用的对象,并且不会被轻易回收的大对象的存在。

六. 永久代(1.8之后消失了)-------取而代之的是元空间

虽然SEJDK1.8,但是JavaEE还是JDK1.7呢.

永久代时在堆内存之中保存的,但是永久代不会被回收,比如inter()方法产生的对象,是不会被回收的。如果操作不当,导致永久代中的数据过大,这个时候程序会抛出OOM异常。

七. 元空间

唯一的区别是永久代使用的堆内存空间,而元空间时使用的物理内存,直接受到本地的物理内存限制。

参考文献:

https://blog.csdn.net/SEU_Calvin/article/details/51404589

《深入理解JAVA虚拟机》

李兴华老师的《Java内存模型》

转载于:https://www.cnblogs.com/Hermioner/p/10088266.html

JVM02----垃圾收集上(堆)相关推荐

  1. 《深入理解Java虚拟机》(第二版)学习3:垃圾收集器

    垃圾收集器 如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. 我们这里讨论的收集器主要是基于JDK 1.7 Update 14之后的 Hotspot VM . Serial 收 ...

  2. 关于Java 垃圾收集器你应该知道这些

    如果Java虚拟机中标记清除算法.标记整理算法.复制算法.分代算法这些属于GC收集算法中的方法论,那么"GC收集器"则是这些方法论的具体实现. 概念准备 下面了解几个概念以帮助后面 ...

  3. Jvm 系列(三):GC 算法 垃圾收集器

    这篇文件将给大家介绍GC都有哪几种算法,以及JVM都有那些垃圾回收器,它们的工作原理. 概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 ...

  4. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,G ...

  5. HotSpot JVM 垃圾收集原理

    目的: 本文描述了Sun公司的HotSpot Java虚拟机的垃圾收集工作原理.以便为更多Java爱好者在设计,开发以及部署时带来更多便利和益处. 摘要: JVM规范中要求任何实现JVM的实现必须要提 ...

  6. 深入理解JVM(5) : Java垃圾收集器

    如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现. Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都可能会有很大差 ...

  7. JVM(3):Java GC算法 垃圾收集器

    概述 垃圾收集 Garbage Collection 通常被称为"GC",它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数 ...

  8. Java 理论与实践: 垃圾收集简史

    垃圾收集的好处是无可争辩的 ―― 可靠性提高.使内存管理与类接口设计分离,并使开发者减少了跟踪内存管理错误的时间.著名的悬空指针和内存泄漏问题在 Java 程序中再也不会发生了(Java 程序可能会出 ...

  9. jvm在windows和linux,理解JVM如何使用Windows和Linux上的本机内存

    欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入 Java 运行时如何使用本机内存 Java 运行时是一个操作系统进程,它会受到我在上一节中列出的硬件和操作系统局限性的限制. ...

  10. 理解JVM如何使用Windows和Linux上的本机内存

    转至:http://www.chineselinuxuniversity.net/articles/23291.shtml 摘要:Java™ 堆耗尽并不是造成 java.lang.OutOfMemor ...

最新文章

  1. CUMCM:05A长江水质综合评价与预测
  2. java的input不能更改,无法将方法响应标头Content-Type更改为application / xml
  3. linux java 环境配置_linux下java开发环境配置
  4. 20 Alarms, sigaction(), and Reentrant System Calls
  5. tensorflow基础:tf.data.Dataset.from_tensor_slices()
  6. android中openMax的实现
  7. selenium+python模拟键盘鼠标操作,python3.6安装pyUserInput
  8. Open Cube 时信魔方介绍
  9. 计算机怎么清理CAD,CAD遇到病毒怎么清理?别慌,教你四个方法搞定它
  10. 图像匹配 | 论文与方法整理
  11. 声音文件格式、常见的数字音频格式
  12. 加密保护软件 WinLicense 注册常见问题(二)
  13. mysql中的是和否是什么数据类型,Access中是/否数据类型是怎样处理的
  14. linux系统怎么数据恢复,linux系统数据恢复
  15. php获取农历日期节日
  16. 支付设计白皮书:支付系统的总架构
  17. 【测试】抓包技术哪家强?关于Burp、Fiddler、Charles三个工具的抓包测试
  18. Python爬虫 scrapy框架爬取某招聘网存入mongodb解析
  19. 一篇文章,带你走进Java
  20. 寄存器(8086CPU)概述与作用

热门文章

  1. 关于本次课堂代码的练习
  2. PHP之常用设计模式
  3. rsync实时同步服务部署
  4. MySQL查询表的所有列名,用逗号拼接
  5. java第一次作业计科2班马浩加
  6. The file “XXX.app” couldn’t be opened because you don’t have permission to view it.问题修复...
  7. html span标签 不换行(有时span带中文时候是可以自动换行的)
  8. Linux常用指令---netstat(网络端口)
  9. jQuery操作Table学习总结(转)
  10. mysql创建数据库与表_PHP MySQL 创建数据库和表 之 Create