文档章节

jvm的内存回收和垃圾回收器

qingfeng哥
 qingfeng哥
发布于 2014/06/05 11:53
字数 2065
阅读 407
收藏 9

jvm的内存回收和垃圾收集器

1、为什么要垃圾回收器

内存很宝贵,有限

内存泄露:该释放的内存没有而且永远没机会被释放,导致内存耗尽

内存溢出:分配不到内存了

C++中内存分配和释放完全自主,但智者千虑必有一种内存泄露的可能
要是有自动的、动态的内存分配的语言就好了,
既然能自动分配内存,那就必须得有配套的能自动回收(释放)这些内存 的机制

早在java之前就有语言能自动分配内存和自动回收内存(如Lisp),相比内存自动分配,内存自动回收更为重要和关键,因为内存是很宝贵的有限资源,这是个很高深的研究课题,主要有三个疑问:
    哪些内存需要回收           什么时候回收(释放)             怎么回收 

这些需要释放回收的内存也换个叫法就是 内存垃圾
于是解答上述问题就产生了各式垃圾回收器garbage collect-GC

jvm采用自动内存管理,并屏蔽指针这个反人类的东西,让很多人喜欢上java

2、了解jvm的内存布局

线程私有:jvm栈stack(该栈中push和pop的是带有复杂数据的栈帧)、
              pc计数器(指明正在执行哪条指令了)、
              本地方法栈
              这三个区的内存 随着线程的生灭而分配和释放,
              他们
需要的内存大小在类结构确定后、编译期就可以基本确定,gc基本不管这块

线程共享:堆heap和方法区method area(含有运行时常量区)
              堆中有多少对象非得跑起来才能确定的
              方法区中的类结构信息等数据是动态加载进来的
              都是不确定的内存分配,这两块才是GC的主战场

有了内存布局的宏观认识,我们需要知道

3、怎么限制各个区的大小

即jvm运行参数,以下参数是hotspot的参数,和怎样人为来产生溢出

1、heap内存大小:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
                          最小        最大                oom时dump溢出时内存堆转储快照

溢出方法:不断的生成对象的实例,且不置为null

2、方法区内存大小:-XX:PermSize=20M -XX:MaxPermSize=30M

溢出方法:不断的通过反射生成新的类

3、jvm栈和本地方法栈的大小:-Xss30M -Xoss10M

溢出方法:方法递归不返回,大量线程

4、直接内存大小:-XX:MaxDirectMemorySize=20M  如果没设置的话则默认与heap堆的最大值一样(-Xmx)

溢出方法:反射获取Unsafe类的实例,然后不停的分配内存allocateMemory()

好了,针对堆和方法区,回到垃圾回收器要解决的三个问题:

4、哪些内存需要回收---对象的死活

经典引用计数法:给对象配个引用计数器,每次引用就+1,引用失效时-1 计数为0时,表明对象不再被使用
jvm没有采用引用计数器算法,因为 有对象间互相循环引用导致无法释放的问题(php、python)

jvm采用根搜索算法-对象引用遍历法           GC Roots Tracing

基本思路:采用图论知识
从一系列名为 GC Roots的对象节点出发,向下搜索,搜索走过的路径为引用链,如果一个对象和根root之间没有任何引用链可通(不可达),则认为该对象没有用了,可以死去,被标记为可回收对象

可以作为GC Roots的对象:
    栈帧中的引用的对象
    方法区中:类静态属性引用的对象、常量引用的对象
   本地方法栈中:JNI的引用的对象

?怎么回收

5、垃圾回收算法

明确 所有垃圾回收时刻都会发生  全停顿 stop the world, 应该尽量减短这个时间

产生了那么多死对象,得想办法回收他们,再入轮回。怎么个做法?基本的思路有四种:

1、标记-清理(mark-sweep)算法:两阶段,第一遍扫描标记哪些对象已死,第二遍扫描清除标死的对象

缺点:两次遍历效率不高,清除后内存产生不连续的碎片

2、复制算法copying:将内存均分,每次在其中一块分配对象,快用完时将还活着的对象都复制到 另一块上,清空已使用的那块即可。代价是内存减半,一点优化是不均分

3、标记-整理(mark-compact)算法,这是标记-清理法的改进,一遍标记并将活的对象移到内存区的一端,然后清理边界外的死对象即可


GC假设

大多数对象会很快变得不可达
只有很少的由老对象(创建时间较长的对象)指向新生对象的引用


由上述对象死活判断依据、GC假设、加上统计数据的发现,可以将对象分为不同的generation

6、JVM分代内存回收

回收之前先了解内存的分配规则,之前我去了解了下Node.js的v8 js引擎的垃圾回收机制 发现这些虚拟机都采用相类似的方法和算法哦

统计知识的应用 
按对象存活时间将对象分配到不同的内存区域,这些区域叫不同的分代 
垃圾回收针对分代对象的特征采用适宜的算法进行回收

将内存再次分区,根据对象存活时间长短将其分配到不同的区域(分代)上,一般分代回收法将内存分成三代:
新生代Eden Gen:该内存区中的对象存活时间短,很快不可达,对象一般也比较小
老生代Old Gen:该内存区中主要是老对象(经过几次回收后还可达的对象)、大对象,占用空间比新生代多
永生代:方法区

内存分配规则及gc算法:
1、新对象一般在新生代Eden中分配,Eden区没足够内存时触发新生代的一次Minor GC,Eden中对象很快死去,基本采用的是 复制算法copying:将内存均分,每次在其中一块分配对象,快用完时将还活着的对象都复制到 另一块上,清空已使用的那块即可。代价是内存减半,一点优化是不均分,而分为一块较大的Eden区和两块较小的survivor区,因为存活的对象不多。每次使用一块survivor和eden,gc时将其中的或对象都拷贝到未使用的那个survivor中,如果那个没使用的survivor空间不够则直接担保分配到 老生代,如果老生代都不够则进行老生代的gc(full Gc)。


2、大对象(很长的字符串、数组等)直接在老生代分配
分代转换:新生代中的对象经过几次gc后仍然存在,达到-XX:MaxTenuringThreshold配置的年龄值(次数)时,这些对象 晋升(转移)到老生代;
分配担保:minor gc会检测之前每次回收晋升到老生代的对象容量的平均值作为经验值,与老生代的剩余空间作比较,如果大于,则直接对老生代进行major gc(Full gc),如果小于,且存活的对象大于survivor空间,则该对象也转移到老生代
老生代存活的对象多且大,一般采用标记清理或标记-整理方法来gc

有了以上内存区的分代和几种基本gc算法,产生了多种具体的垃圾收集器

具体实现

7、JDK的垃圾收集器

JDK7一共有5种GC类型:

参考吧:http://www.importnew.com/1993.html

  1. Serial GC
  2. Parallel GC
  3. Parallel Old GC (Parallel Compacting GC)
  4. Concurrent Mark & Sweep GC  (or “CMS”)
  5. Garbage First (G1) GC

© 著作权归作者所有

共有 人打赏支持
qingfeng哥

qingfeng哥

粉丝 44
博文 126
码字总数 64298
作品 0
湛江
技术主管
私信 提问
加载中

评论(1)

jdk2010
jdk2010
mark
Java GC系列:Java垃圾回收详解

Java的内存分配与回收全部由JVM垃圾回收进程自动完成。与C语言不同,Java开发者不需要自己编写代码实现垃圾回收。这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序。 ...

满风
2015/04/10
0
0
My java——JVM(垃圾回收)四

续My java——JVM(内存域) 中讲述了Java在JVM中的内存使用,其实在我们出来java程序时基本上有两个地方的内存处理 一是栈、二是堆,JVM会自动回收堆中的内存,也就我们所说的垃圾回收,那J...

tngou
2013/03/20
0
0
Java finalize方法

《JAVA编程思想》: java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize()。 (1).对象不一定会被回收。 (2).垃圾回收不是析构函数。 (3).垃圾回收只与内存有关。 (4)....

清风伴月
2017/10/22
0
0
《成神之路-基础篇》JVM——垃圾回收(已完结)

Java内存模型,Java内存管理,Java堆和栈,垃圾回收 本文是[《成神之路系列文章》][1]的第一篇,主要是关于JVM的一些介绍。 持续更新中 Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收 ...

05/05
0
0
JVM性能优化, Part 3 垃圾回收

ImportNew注:本文是JVM性能优化 系列-第3篇-《JVM性能优化, Part 3 —— 垃圾回收》 第一篇 《JVM性能优化, Part 1 ―― JVM简介 》 第二篇《JVM性能优化, Part 2 ―― 编译器》 Java平台...

梁杰_Jack
2014/10/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mariadb二进制包安装,Apache安装

安装mariadb 下载二进制包并解压 [root@test-a src]# wget https://downloads.mariadb.com/MariaDB/mariadb-10.2.6/bintar-linux-glibc_214-x86_64/mariadb-10.2.6-linux-glibc_214-x86_64.t......

野雪球
16分钟前
0
0
ConcurrentHashMap 高并发性的实现机制

ConcurrentHashMap 的结构分析 为了更好的理解 ConcurrentHashMap 高并发的具体实现,让我们先探索它的结构模型。 ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEnt...

TonyStarkSir
今天
3
0
大数据教程(7.4)HDFS的java客户端API(流处理方式)

博主上一篇博客分享了namenode和datanode的工作原理,本章节将继前面的HDFS的java客户端简单API后深度讲述HDFS流处理API。 场景:博主前面的文章介绍过HDFS上存的大文件会成不同的块存储在不...

em_aaron
昨天
2
0
聊聊storm的window trigger

序 本文主要研究一下storm的window trigger WindowTridentProcessor.prepare storm-core-1.2.2-sources.jar!/org/apache/storm/trident/windowing/WindowTridentProcessor.java public v......

go4it
昨天
6
0
CentOS 生产环境配置

初始配置 对于一般配置来说,不需要安装 epel-release 仓库,本文主要在于希望跟随 RHEL 的配置流程,紧跟红帽公司对于服务器的配置说明。 # yum update 安装 centos-release-scl # yum ins...

clin003
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部