最近做一个ETL的项目模块,经常由于查询数据量比较大用消息中间件MQ时引起了内存溢出的报错。做完后没事研究了一下JVM和垃圾回收的相关知识点。

一:垃圾回收机制的意义

java  语言中一个显著的特点就是引入了java回收机制,是c++程序员最头疼的内存管理的问题迎刃而解,它使得java程序员在编写程序的时候不在考虑内存管理。由于有个垃圾回收机制,java中的额对象不在有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存;

说到这,不得不提起内存泄漏(memory leak)和内存溢出(out of memory)

内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

内存溢出:指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。

通俗的说就是停车场(堆)保安(gc)让很久不用的废弃车子(无用的对象)从车位上挪走,但是这个车子又没办法挪走。这就是内存泄漏。停车场所有的车位都有车子占用了,再来车子没地了,或者说给你一个小汽车的停车位(int),你非要停一辆高铁(Long),这就是内存溢出。

内存泄露量大到一定程度会导致内存溢出。但是内存溢出不一定是内存泄露引起的。

内存泄漏的分类(按发生方式来分类)

  1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
  2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
  3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
  4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏
  1. 内存溢出原因: 
    1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据; 
    2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收; 
    3.代码中存在死循环或循环产生过多重复的对象实体; 
    4.使用的第三方软件中的BUG; 
    5.启动参数内存值设定的过小

内存溢出的解决方案: 

第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)

第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。

第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。


二:垃圾回收策略



分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。

年轻代(Young Generation)

1.所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

2.新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

3.当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

4.新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)

年老代(Old Generation)

1.在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

2.内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

持久代(Permanent Generation)

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。

说到持久代,也称永久代,不得不说一句,在jdk新版本中,已经没有了永久代这个区域。

三.GC(垃圾收集器)

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

Serial收集器(复制算法)

新生代单线程收集器,标记和清理都是单线程,优点是简单高效。

Serial Old收集器(标记-整理算法)

老年代单线程收集器,Serial收集器的老年代版本。

ParNew收集器(停止-复制算法) 

新生代收集器,可以认为是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现。

Parallel Scavenge收集器(停止-复制算法)

并行收集器,追求高吞吐量,高效利用CPU。吞吐量一般为99%, 吞吐量= 用户线程时间/(用户线程时间+GC线程时间)。适合后台应用等对交互相应要求不高的场景。

Parallel Old收集器(停止-复制算法)

Parallel Scavenge收集器的老年代版本,并行收集器,吞吐量优先

CMS(Concurrent Mark Sweep)收集器(标记-清理算法)

高并发、低停顿,追求最短GC回收停顿时间,cpu占用比较高,响应时间快,停顿时间短,多核cpu 追求高响应时间的选择

四:GC的执行机制

由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

Scavenge GC

一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

Full GC

对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

1.年老代(Tenured)被写满

2.持久代(Perm)被写满

3.System.gc()被显示调用

4.上一次GC之后Heap的各域分配策略动态变化

Java 垃圾回收机制原理相关推荐

  1. Java垃圾回收机制(Garbage Collection)

    引用博客地址:http://www.cnblogs.com/ywl925/p/3925637.html 以下两篇博客综合描述Java垃圾回收机制 第一篇:说的比较多,但是不详细 http://www. ...

  2. Java垃圾回收机制与垃圾收集器

    Java垃圾回收机制与垃圾收集器 前言 判定对象是否存活(标记) 引用计数法 可达性分析 算法思想 算法步骤 对象复活 引用概念的完善 垃圾回收算法 标记 - 清除法 标记 - 复制法 标记 - 整理 ...

  3. 【JVM】Java垃圾回收机制(GC)详解

    Java垃圾回收机制(GC)详解 一.为什么需要垃圾回收? 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配不回收,但是事实并非如 ...

  4. java 垃圾回收机制的理解

    1.垃圾回收的意义 在java体系中内存的分和回收是自动化管理的,从而程序员不需要操心内存的分配和是否浪费.javaGC机制能帮我们把不需要的对象占用的内存回收,保证程序高效的运行.由于我们创建的对象 ...

  5. java垃圾回收机制_笔记 | Java垃圾回收机制

    本文经授权转载自程序员杂货铺(ID:speakFramework) 垃圾回收 最近上海的小伙伴是不是要被强垃圾分类搞疯了???哈哈哈哈 上海是个走在前列的城市啊,不光骑自行车闯红灯要被罚钱,垃圾不分类 ...

  6. java垃圾回收机制_JVM的垃圾回收机制——垃圾回收算法

    一.Java垃圾回收机制 在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行.在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者 ...

  7. 36.JVM内存分哪几个区,每个区的作用是什么、如和判断一个对象是否存活、java垃圾回收机制、垃圾收集的方法有哪些、java类加载过程、类加载机制、双亲委派、Minor GC和Major GC

    36.JVM内存分哪几个区,每个区的作用是什么? 37.如和判断一个对象是否存活?(或者GC对象的判定方法) 38.简述java垃圾回收机制? 39.java中垃圾收集的方法有哪些? 40.java类 ...

  8. 深入理解 Java 垃圾回收机制

    转载自 http://www.cnblogs.com/andy-zcx/p/5522836.html 深入理解 Java 垃圾回收机制 一:垃圾回收机制的意义 java  语言中一个显著的特点就是引入 ...

  9. java垃圾回收机制的理解

    Java垃圾回收机制算法 标记----清除算法 复制算法 标记----整理算法 分代收集算法 为什么要进行垃圾回收 因为当一个对象的引用不可达,或者一个对象没有任何引用指向它,那么它就没有必要在内存中 ...

  10. 【Java】Java垃圾回收机制

    Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给 ...

最新文章

  1. android 自定义菜单开发,Android开发学习笔记:浅谈3大类菜单
  2. C 语言中的内存分析
  3. jmeter java性能_jmeter之自定义java请求性能测试
  4. 监控流媒体服务器连接监控摄像头的配置方式 - GB28181和ONVIF
  5. python 依赖包迁移(本地安装)
  6. MFC获取屏幕分辨率
  7. Python+OpenCV:图像Harris角点检测(Harris Corner Detection)
  8. phpcms根据二级栏目列表写的三级栏目列表
  9. MySQL索引类型详解,让MySQL高效运行起来
  10. windows版redis安装教程
  11. iOS 多媒体(一)音频播放
  12. Windows下SVN提交模板制作及应用
  13. html5在线裁剪,HTML5和JQuery裁剪图像实时预览缩略图并上传
  14. Log4j2官方文档翻译--欢迎使用Log4j2!
  15. php暴力引流代码,利用霸屏暴力引流,免费分享霸屏代码
  16. 【前端面试课程重点总结】
  17. Arduino制作一个人体感应灯
  18. Word2Vec+ Word Embedding
  19. 论文笔记MEMC-Net TPAMI
  20. matlab产生单音信号的时域、频域图

热门文章

  1. 电脑打印机print spooler服务总是自动停止的解决方法...
  2. linux查看内存条pn,内存条,详细教您怎么查看内存条的型号。
  3. quartus 13.1自带仿真测试流程
  4. 计算机添加打印机地址簿添加不上,为什么本地打印机添加不上,怎么办?
  5. stm32芯片超时无应答解决
  6. 辐射校正:像元DN值—辐照度—表观反射率—地表反射率
  7. 【安卓作业】星座查询小程序
  8. 使用Kotlin创建动态Android TextWatcher
  9. Linux网络抓包分析工具(tcpdump、wireshark)
  10. iOS申请真机调试证书-图文详解